# -*- coding: utf-8 -*-

##########################################################################
# OpenLP - Open Source Lyrics Projection                                 #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2024 OpenLP Developers                              #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify   #
# it under the terms of the GNU General Public License as published by   #
# the Free Software Foundation, either version 3 of the License, or      #
# (at your option) any later version.                                    #
#                                                                        #
# This program is distributed in the hope that it will be useful,        #
# but WITHOUT ANY WARRANTY; without even the implied warranty of         #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          #
# GNU General Public License for more details.                           #
#                                                                        #
# You should have received a copy of the GNU General Public License      #
# along with this program.  If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
The :mod:`worshipassistant` module provides the functionality for importing
Worship Assistant songs into the OpenLP database.
"""
import csv
import logging
import re

from openlp.core.common import get_file_encoding
from openlp.core.common.i18n import translate
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.importers.songimport import SongImport


log = logging.getLogger(__name__)

EMPTY_STR = 'NULL'


class WorshipAssistantImport(SongImport):
    """
    The :class:`WorshipAssistantImport` class provides the ability to import songs
    from Worship Assistant, via a dump of the database to a CSV file.

    The following fields are in the exported CSV file:

    * ``SONGNR`` Song ID (Discarded by importer)
    * ``TITLE`` Song title
    * ``AUTHOR`` Song author.
    * ``COPYRIGHT`` Copyright information
    * ``FIRSTLINE`` Unknown (Discarded by importer)
    * ``PRIKEY`` Primary chord key (Discarded by importer)
    * ``ALTKEY`` Alternate chord key (Discarded by importer)
    * ``TEMPO`` Tempo (Discarded by importer)
    * ``FOCUS`` Unknown (Discarded by importer)
    * ``THEME`` Theme (Discarded by importer)
    * ``SCRIPTURE`` Associated scripture (Discarded by importer)
    * ``ACTIVE`` Boolean value (Discarded by importer)
    * ``SONGBOOK`` Boolean value (Discarded by importer)
    * ``TIMESIG`` Unknown (Discarded by importer)
    * ``INTRODUCED`` Date the song was created (Discarded by importer)
    * ``LASTUSED`` Date the song was last used (Discarded by importer)
    * ``TIMESUSED`` How many times the song was used (Discarded by importer)
    * ``CCLINR`` CCLI Number
    * ``USER1`` User Field 1 (Discarded by importer)
    * ``USER2`` User Field 2 (Discarded by importer)
    * ``USER3`` User Field 3 (Discarded by importer)
    * ``USER4`` User Field 4 (Discarded by importer)
    * ``USER5`` User Field 5 (Discarded by importer)
    * ``ROADMAP`` Verse order used for the presentation
    * ``FILELINK1`` Associated file 1 (Discarded by importer)
    * ``OVERMAP`` Verse order used for printing (Discarded by importer)
    * ``FILELINK2`` Associated file 2 (Discarded by importer)
    * ``LYRICS`` The song lyrics used for printing (Discarded by importer, LYRICS2 is used instead)
    * ``INFO`` Unknown (Discarded by importer)
    * ``LYRICS2`` The song lyrics used for the presentation
    * ``BACKGROUND`` Custom background (Discarded by importer)
    """
    def do_import(self):
        """
        Receive a CSV file to import.
        """
        # Get encoding
        encoding = get_file_encoding(self.import_source)
        with self.import_source.open('r', encoding=encoding) as songs_file:
            songs_reader = csv.DictReader(songs_file, escapechar='\\')
            try:
                records = list(songs_reader)
            except csv.Error as e:
                self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'),
                               translate('SongsPlugin.WorshipAssistantImport',
                                         'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e))
                return
            except UnicodeDecodeError as e:
                self.log_error(translate('SongsPlugin.WorshipAssistantImport',
                                         'Decoding error: {error}').format(error=e))
                return
        num_records = len(records)
        log.info('{count} records found in CSV file'.format(count=num_records))
        self.import_wizard.progress_bar.setMaximum(num_records)
        # Create regex to strip html tags
        re_html_strip = re.compile(r'<[^>]+>')
        for index, record in enumerate(records, 1):
            if self.stop_import_flag:
                return
            # Ensure that all keys are uppercase
            record = dict((field.upper(), value) for field, value in record.items())
            # The CSV file has a line in the middle of the file where the headers are repeated.
            #  We need to skip this line.
            try:
                if record['TITLE'] == "TITLE" and record['AUTHOR'] == 'AUTHOR' and record['LYRICS2'] == 'LYRICS2':
                    continue
                self.set_defaults()
                verse_order_list = []
                self.title = record['TITLE']
                if record['AUTHOR'] != EMPTY_STR:
                    self.parse_author(record['AUTHOR'])
                if record['COPYRIGHT'] != EMPTY_STR:
                    self.add_copyright(record['COPYRIGHT'])
                if record['CCLINR'] != EMPTY_STR:
                    self.ccli_number = record['CCLINR']
                if record['ROADMAP'] != EMPTY_STR:
                    verse_order_list = [x.strip() for x in record['ROADMAP'].split(',')]
                lyrics = record['LYRICS2']
            except UnicodeDecodeError as e:
                self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record {count:d}').format(count=index),
                               translate('SongsPlugin.WorshipAssistantImport',
                                         'Decoding error: {error}').format(error=e))
                continue
            except TypeError as e:
                self.log_error(translate('SongsPlugin.WorshipAssistantImport',
                                         'File not valid WorshipAssistant CSV format.'),
                               'TypeError: {error}'.format(error=e))
                return
            except KeyError as e:
                self.log_error(translate('SongsPlugin.WorshipAssistantImport',
                                         'File not valid WorshipAssistant CSV format.'),
                               'KeyError: {error}'.format(error=e))
                return
            verse = ''
            used_verses = []
            verse_id = VerseType.tags[VerseType.Verse] + '1'
            for line in lyrics.splitlines():
                if line.startswith('['):  # verse marker
                    # Add previous verse
                    if verse:
                        # remove trailing linebreak, part of the WA syntax
                        self.add_verse(verse[:-1], verse_id)
                        used_verses.append(verse_id)
                        verse = ''
                    # drop the square brackets
                    right_bracket = line.find(']')
                    content = line[1:right_bracket].lower()
                    match = re.match(r'(\D*)(\d+)', content)
                    if match is not None:
                        verse_tag = match.group(1)
                        verse_num = match.group(2)
                    else:
                        # otherwise we assume number 1 and take the whole prefix as the verse tag
                        verse_tag = content
                        verse_num = '1'
                    verse_index = VerseType.from_loose_input(verse_tag) if verse_tag else 0
                    verse_tag = VerseType.tags[verse_index]
                    # Update verse order when the verse name has changed
                    verse_id = verse_tag + verse_num
                    # Make sure we've not choosen an id already used
                    while verse_id in verse_order_list and content in verse_order_list:
                        verse_num = str(int(verse_num) + 1)
                        verse_id = verse_tag + verse_num
                    if content != verse_id:
                        for i in range(len(verse_order_list)):
                            if verse_order_list[i].lower() == content.lower():
                                verse_order_list[i] = verse_id
                else:
                    # add line text to verse. Strip out html
                    verse += re_html_strip.sub('', line) + '\n'
            if verse:
                # remove trailing linebreak, part of the WA syntax
                if verse.endswith('\n\n'):
                    verse = verse[:-1]
                self.add_verse(verse, verse_id)
                used_verses.append(verse_id)
            if verse_order_list:
                # Use the verse order in the import, but remove entries that doesn't have a text
                cleaned_verse_order_list = []
                for verse in verse_order_list:
                    if verse in used_verses:
                        cleaned_verse_order_list.append(verse)
                self.verse_order_list = cleaned_verse_order_list
            if not self.finish():
                self.log_error(translate('SongsPlugin.WorshipAssistantImport',
                                         'Record {count:d}').format(count=index) +
                               (': "' + self.title + '"' if self.title else ''))
