# _user_dir_migrator_base.py
#
# Project: AutoArchive
# License: GNU GPLv3
#
# Copyright (C) 2003 - 2026 Róbert Čerňanský



from abc import ABC, abstractmethod

from AutoArchive._infrastructure.app_dir.app_dir import AppDir
from AutoArchive._ui.cmdline._cmdline_ui import CmdlineUi
from AutoArchive._update._file_system import _FileSystem



class _UserDirMigratorBase(ABC):

    def __init__(self, fileSystem: _FileSystem, oldUserDir: AppDir, newUserDir: AppDir, cmdlineUi: CmdlineUi):
        self.__fileSystem = fileSystem
        self.__oldUserDir = oldUserDir
        self.__newUserDir = newUserDir
        self.__cmdlineUi = cmdlineUi



    def migrate(self):
        if not self.__isMigrated():
            if self.__isPreconditionsMet():
                self.__cmdlineUi.showWarning(f"Migration of {self.dirName_} directory is needed.")
                if self.__checkMigrationIntegrity():
                    try:
                        self.__makeMigration()
                    except OSError as ex:
                        self.__cmdlineUi.showError(f"Migration failed with error: {ex}.")
        else:
            self.__checkMigrationIntegrity()



    @property
    @abstractmethod
    def dirName_(self) -> str:
        pass



    @property
    def oldUserDir_(self) -> AppDir:
        return self.__oldUserDir



    @property
    def fileSystem_(self) -> _FileSystem:
        return self.__fileSystem



    @property
    def cmdLineUi_(self) -> CmdlineUi:
        return self.__cmdlineUi



    @abstractmethod
    def moveContent_(self, oldUserDir: AppDir, newUserDir: AppDir):
        pass



    @abstractmethod
    def isOldUserDirExisting_(self) -> bool:
        pass



    def __isMigrated(self) -> bool:
        return self.__fileSystem.exists(self.__newUserDir.path) and self.__newUserDir.isCurrentVersion()



    def __isPreconditionsMet(self) -> bool:
        return self.isOldUserDirExisting_() or self.__fileSystem.exists(self.__newUserDir.path)



    def __checkMigrationIntegrity(self) -> bool:
        if self.__oldUserDir.path == self.__newUserDir.path:
            return True

        if not self.isOldUserDirExisting_():
            return True

        if self.__oldUserDir.isCurrentVersion():
            self.__showMigrationError(
                f"Found {self.dirName_} directory in legacy path '{self.__oldUserDir.path}'. Current " +
                f"{self.dirName_} directory path is: '{self.__newUserDir.path}'. Remove the directory in the " +
                "legacy path after checking that its content was migrated to the new one.")
            return False
        if self.__fileSystem.exists(self.__newUserDir.path):
            self.__showMigrationError(
                f"Found legacy {self.dirName_} directory in '{self.__oldUserDir.path}'. Current {self.dirName_} " +
                f"directory is: '{self.__newUserDir.path}'. Remove the legacy directory after checking that its " +
                "content was migrated to the new one.")
            return False

        return True



    def __makeMigration(self):
        if self.__fileSystem.exists(self.__newUserDir.path):
            self.__showMigrationInfo(
                f"Migrating {self.dirName_} directory in path '{self.__newUserDir}' ...setting directory version.")
            self.__newUserDir.setToCurrentVersion()
            return

        self.__showMigrationInfo(
            f"Moving {self.dirName_} directory from legacy path '{self.__oldUserDir}' to current " +
            f"path: '{self.__newUserDir.path}'.")

        self.moveContent_(self.__oldUserDir, self.__newUserDir)

        self.__newUserDir.setToCurrentVersion()



    def __showMigrationInfo(self, message):
        self.__cmdlineUi.showInfo(f"Migration: {message}")



    def __showMigrationError(self, message):
        self.__cmdlineUi.showError(f"Migration: {message}")
