'''
/***************************************************************************
Name	   :  workspace_setup_controller.py
Description:  Workspace Settings for FEWSTools plugin, updated from QGIS2
copyright  :  (C) 2019-2023 by FEWS
email      :  minxuansun@contractor.usgs.gov
Modified   :  02/07/2020 - CHOLEN - Add fix_os_sep_in_path to path builders
              05/19/2020 msun - Adjusted default workspace creation
              06/02/2020 - CHOLEN - Stopped copy into a folder that already has
                                    a GeoCLIM folder in place.
              07/14/2020 - CHOLEN - Log on exceptions
              02/22/2021 - cholen - Add call for initialize_default_output_dir
              02/23/2022 - cholen - Codebase consistency changes
              06/23/2022 - cholen - Use update_region_filepaths
              07/25/2022 - cholen - Add migrations
              08/08/2022 - cholen - Disable ok if nothing selected.
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
'''
import getpass
import os
import platform
import shutil
import zipfile

from PyQt5 import QtCore
from PyQt5.QtWidgets import QMessageBox, QDialog, QFileDialog
from qgis.core import QgsMessageLog, Qgis

from fews_tools import fews_tools_config as config
from fews_tools.utilities import database_utilities as db_util

from fews_tools.models.workspace_setup_model import WorkspaceSetupModel
from fews_tools.models.datasets_model import DatasetsModel
from fews_tools.models.region_model import RegionModel
from fews_tools.forms.Ui_WorkspaceSettings import Ui_WorkspaceSettings


class WorkspaceSetupController(QDialog):
    '''
    Class to handle the workspace settings for FEWSTools plugin
    '''

    def __init__(self):
        QDialog.__init__(self)
        self.ui = Ui_WorkspaceSettings()
        self.ui.setupUi(self)
        self.ui.wrkSpaceLineEdit.setEnabled(False)
        self.ui.browseButton.clicked.connect(self.browse_workspace)
        self.ui.cancelButton.clicked.connect(self.cancel_browse)
        self.ui.okButton.clicked.connect(self.update_db_and_move_files)
        self.wrksp_setup = WorkspaceSetupModel()
        self.ds_info = DatasetsModel()
        self.reg_info = RegionModel()
        self.move = False
        self.new_workspace = None
        self.old_workspace = self.wrksp_setup.get_workspace()
        self.ui.okButton.setEnabled(False)

        # force user to select a workspace if none exists
        if not self.old_workspace:
            self.browse_workspace()

        self.ui.existWrkspace.setText(self.old_workspace)

    def move_workspace_files(self):
        '''
        Move the workspace.
        '''
        try:
            shutil.move(self.old_workspace, self.new_workspace)
        except BaseException:
            QgsMessageLog.logMessage(
                'Exception - Workspace move failed',
                level=Qgis.Critical)

    def build_default_workspace(self, workspace_dir):
        '''
        Create a default workspace. This extracts the zip provided with the
        plugin and places it in specific directory.
        Args: workspace_dir(str) - The directory to place workspace folder.
                                   If empty string, use default workspace directory
        '''
        default_zip = self.wrksp_setup.fix_os_sep_in_path(os.path.join(
            os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
            "DefaultWorkspaceTemplate.zip"))
        default_unzip = self.wrksp_setup.fix_os_sep_in_path(
            os.path.join(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
        src = self.wrksp_setup.fix_os_sep_in_path(
            os.path.join(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__))),
                         "DefaultWorkspaceTemplate",
                         config.WORKSPACE))
        if workspace_dir:
            default_workspace = self.wrksp_setup.fix_os_sep_in_path(workspace_dir)
        else:
            # TODO - Complete os independence here, needs testing
            if 'Windows' in platform.platform():
                default_workspace = self.wrksp_setup.fix_os_sep_in_path(
                    os.path.join('C:' + os.sep, 'Users',
                                 getpass.getuser(),
                                 'Documents', config.WORKSPACE))
            else:
                # Linux and MacOS
                default_workspace = self.wrksp_setup.fix_os_sep_in_path(
                    os.path.join(os.sep + 'Users', getpass.getuser(), config.WORKSPACE))
        if default_workspace[-1] == os.sep:
            old_workspace = os.path.join(os.path.dirname(os.path.dirname(default_workspace)), config.OLD_WORKSPACE)
        else:
            old_workspace = os.path.join(os.path.dirname(default_workspace), config.OLD_WORKSPACE)
        if os.path.exists(default_workspace):
            reply = QMessageBox.question(
                self,
                'Workspace already exists.\n',
                'The workspace - \n' + default_workspace +
                '\n exists. \nDo you want to rename it to "' + config.OLD_WORKSPACE + '" '
                'and create a new workspace by using the default workspace template? '
                'That means all of your current data will be moved to ' + old_workspace + '\n'
                '(Warning - if ' + old_workspace + ' exists, it will be replaced by the '
                'current workspace ' + default_workspace + ')',
                QMessageBox.Yes, QMessageBox.No)
        else:
            reply = QMessageBox.Yes
            QMessageBox.information(self,
                                    'No existing workspace',
                                    'Creating default workspace\n' +
                                    default_workspace,
                                    QMessageBox.Ok)
        if reply == QMessageBox.Yes:
            # create default workspace template
            try:
                if os.path.exists(old_workspace):
                    # remove old existing workspace, replace it with the current workspace
                    shutil.rmtree(old_workspace)
                if os.path.exists(default_workspace):
                    shutil.copytree(default_workspace, old_workspace)
                    shutil.rmtree(default_workspace)
                # unzip the default workspace
                zip_ref = zipfile.ZipFile(default_zip, 'r')
                zip_ref.extractall(default_unzip)
                zip_ref.close()
                shutil.copytree(src, default_workspace)
            except BaseException:
                QgsMessageLog.logMessage(
                    'Exception - Unzipping default Workspace failed',
                    level=Qgis.Critical)
        try:
            # update the db entries to point to the default workspace
            self.wrksp_setup.set_workspace(default_workspace)
            self.ds_info.update_dataset_filepaths(default_workspace)
            self.reg_info.update_region_filepaths(default_workspace)
            # set initial default output dir
            self.wrksp_setup.initialize_default_output_dir(
                default_workspace)
        except BaseException:
            QgsMessageLog.logMessage(
                'Exception - Updating database paths for default Workspace failed',
                level=Qgis.Critical)

    def browse_workspace(self):
        '''
        Browse to desired location of workspace and updates the database value.
        '''
        folder =\
            QFileDialog.getExistingDirectory(None,
                                             "Select Workspace",
                                             QtCore.QDir.currentPath())
        new_path = os.path.join(folder, config.WORKSPACE)
        # check for a GeoCLIM folder in selected location
        # if exists then give dialog and return, we will not allow a folder
        # that already contains a 'GeoCLIM' folder, because the copy used
        # will actually create a nested 'GeoCLIM' folder within the existing
        # 'GeoCLIM' folder
        if os.path.exists(new_path):
            QMessageBox.warning(
                self,
                "Workspace Move Not Allowed",
                ("There is already a folder at that location.\n"
                 "The workspace cannot be moved there.\n"
                 "Please select a valid location."),
                QMessageBox.Ok)
        elif os.path.exists(folder):
            self.new_workspace = self.wrksp_setup.fix_os_sep_in_path(new_path)
            self.ui.wrkSpaceLineEdit.setText(self.new_workspace)
            self.ui.okButton.setEnabled(True)

    def cancel_browse(self):
        '''
        Cancel - reset new workspace to none.
        '''
        self.new_workspace = None

    def update_db_and_move_files(self):
        '''
        Update the database tables and move the files if necessary
        to the location of self.new_workspace.
        '''
        try:
            # don't allow a copy if the workspace is already there
            if self.old_workspace == self.new_workspace:
                QMessageBox.warning(
                    self,
                    "Workspace Move Not Allowed",
                    ("The new workspace location is the same as the "
                     "current workspace location.\n"
                     "The workspace will not be moved."),
                    QMessageBox.Ok)
            else:
                reply = QMessageBox.question(
                    self,
                    "Workspace Move Confirmation",
                    ("1) Before moving a workspace it is recommended "
                     "to create a backup.\n\n"
                     "2) Be aware that moving a large workspace can "
                     "take significant time.\n"
                     "3) Ensure enough disk space is available for the new workspace.\n"
                     "A message box will confirm when the move "
                     "has completed.\n"
                     "QGIS and the fews_tools plugin will be locked "
                     "until the move is complete.\n\n"
                     "4) Moving workspace from:\n   " +
                     self.old_workspace + "\n   to:\n   " +
                     self.new_workspace +
                     ".\n\nDo you want to continue?"),
                    QMessageBox.Yes,
                    QMessageBox.Cancel)
                if reply == QMessageBox.Yes:
                    # move the workspace files
                    self.move_workspace_files()
                    # update the database paths
                    self.wrksp_setup.set_workspace(self.new_workspace)
                    self.ds_info.update_dataset_filepaths(
                        self.new_workspace)
                    self.reg_info.update_region_filepaths(
                        self.new_workspace)
        except BaseException:
            # on any error put the db settings back to what they were
            self.wrksp_setup.set_workspace(self.old_workspace)
            self.ds_info.update_dataset_filepaths(self.old_workspace)
            self.reg_info.update_region_filepaths(self.old_workspace)
            QgsMessageLog.logMessage(
                'Exception - Updating workspace values failed',
                level=Qgis.Critical)
        # only do this step if everything else succeeds
        self.wrksp_setup.set_output_dir(
            self.old_workspace, self.new_workspace)
        QMessageBox.information(
            self,
            "Move Workspace Succeeded",
            "The workspace was successfully moved.",
            QMessageBox.Ok)

    def migrate_database(self):
        '''
        Update the database tables workspace path.
        '''
        try:
            QMessageBox.information(
                        None,
                        "Migrating database!",
                        ('Migrating old database file:\n ' +
                         config.OLD_DB_FILE +
                         '\nto new_database_file:\n' + config.DB_FILE),
                         QMessageBox.Ok)
            # handle updating the new fews_tools db file with paths
            # from old geoclim db file, so don't use the model function!!
            sql = 'SELECT Workspace FROM ' + self.wrksp_setup.setup_table_name
            workspace_path = db_util.query_db(
                sql, None, False, config.OLD_DB_FILE)[0]
            # update the worksapce
            self.wrksp_setup.set_workspace(workspace_path)
            # update the paths
            self.ds_info.update_dataset_filepaths(workspace_path)
            self.reg_info.update_region_filepaths(workspace_path)
            self.wrksp_setup.set_output_dir(
                    self.old_workspace, workspace_path)
            # get any non-default datasets and regions from geoclim db
            self.ds_info.migrate_datasets()
            self.reg_info.migrate_regions(workspace_path)
        except BaseException:
            QgsMessageLog.logMessage(
                'Exception - Migrating to ' + config.DB_FILE +  'failed',
                level=Qgis.Critical)
