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



__all__ = ["TestUserDirMigratorBase"]



import unittest
from typing import override, Sequence

from mock import MagicMock

from AutoArchive._infrastructure.app_dir.app_dir import AppDir
from AutoArchive._ui.cmdline._cmdline_ui import CmdlineUi
from AutoArchive._update._file_system import _FileSystem
from AutoArchive._update._user_dir_migrator_base import _UserDirMigratorBase
from AutoArchive._update.tests._update_test_utils import _UpdateTestUtils



class TestUserDirMigratorBase(unittest.TestCase):

    __OLD_USER_DIR_PATH = "test old user directory path"
    __NEW_USER_DIR_PATH = "test new user directory path"



    def test_PathsAreDifferent_OldDirNotExists_NewDirNotExists(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirNotExists_NewDirExistsAndIsNotCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = False)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__NEW_USER_DIR_PATH])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_called_once()



    def test_PathsAreDifferent_OldDirNotExists_NewDirExistsAndIsCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = True)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__NEW_USER_DIR_PATH])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirExistsAndIsNotCurrent_NewDirNotExists(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = False)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__OLD_USER_DIR_PATH])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertSequenceEqual((oldUserDirMock, newUserDirMock), userDirMigratorStub.moveContentCalledWith)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_called_once()



    def test_PathsAreDifferent_OldDirExistsAndIsNotCurrent_NewDirExistsAndIsNotCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = False)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = False)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(
            existingPaths = [self.__OLD_USER_DIR_PATH, self.__NEW_USER_DIR_PATH])

        cmdlineUiMock = MagicMock(spec_set = CmdlineUi)

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, cmdlineUiMock)
        userDirMigratorStub.migrate()

        cmdlineUiMock.showError.assert_called_once()
        self.assertIn(f"Found legacy {userDirMigratorStub.dirName_} directory in '{self.__OLD_USER_DIR_PATH}'",
            cmdlineUiMock.showError.call_args[0][0])
        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirExistsAndIsNotCurrent_NewDirExistsAndIsCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = False)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = True)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(
            existingPaths = [self.__OLD_USER_DIR_PATH, self.__NEW_USER_DIR_PATH])
        cmdlineUiMock = MagicMock(spec_set = CmdlineUi)

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, cmdlineUiMock)
        userDirMigratorStub.migrate()

        cmdlineUiMock.showError.assert_called_once()
        self.assertIn(f"Found legacy {userDirMigratorStub.dirName_} directory in '{self.__OLD_USER_DIR_PATH}'",
            cmdlineUiMock.showError.call_args[0][0])
        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirExistsAndIsCurrent_NewDirNotExists(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = True)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__OLD_USER_DIR_PATH])
        cmdlineUiMock = MagicMock(spec_set = CmdlineUi)

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, cmdlineUiMock)
        userDirMigratorStub.migrate()

        cmdlineUiMock.showError.assert_called_once()
        self.assertIn(f"Found {userDirMigratorStub.dirName_} directory in legacy path '{self.__OLD_USER_DIR_PATH}'",
            cmdlineUiMock.showError.call_args[0][0])
        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirExistsAndIsCurrent_NewDirExistsAndIsNotCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = True)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = False)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(
            existingPaths = [self.__OLD_USER_DIR_PATH, self.__NEW_USER_DIR_PATH])

        cmdlineUiMock = MagicMock(spec_set = CmdlineUi)

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, cmdlineUiMock)
        userDirMigratorStub.migrate()

        cmdlineUiMock.showError.assert_called_once()
        self.assertIn(f"Found {userDirMigratorStub.dirName_} directory in legacy path '{self.__OLD_USER_DIR_PATH}'",
            cmdlineUiMock.showError.call_args[0][0])
        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreDifferent_OldDirExistsAndIsCurrent_NewDirExistsAndIsCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = True)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__NEW_USER_DIR_PATH, isCurrent = True)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(
            existingPaths = [self.__OLD_USER_DIR_PATH, self.__NEW_USER_DIR_PATH])
        cmdlineUiMock = MagicMock(spec_set = CmdlineUi)

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, cmdlineUiMock)
        userDirMigratorStub.migrate()

        cmdlineUiMock.showError.assert_called_once()
        self.assertIn(f"Found {userDirMigratorStub.dirName_} directory in legacy path '{self.__OLD_USER_DIR_PATH}'",
            cmdlineUiMock.showError.call_args[0][0])
        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreSame_DirNotExists(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



    def test_PathsAreSame_DirExistsAndIsNotCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = False)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = False)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__OLD_USER_DIR_PATH])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_called_once()



    def test_PathsAreSame_DirExistsAndIsCurrent(self):
        oldUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = True)
        newUserDirMock = _UpdateTestUtils.setupAppDirMock(path = self.__OLD_USER_DIR_PATH, isCurrent = True)
        fileSystemMock = _UpdateTestUtils.setupFileSystemMock(existingPaths = [self.__OLD_USER_DIR_PATH])

        userDirMigratorStub = _UserDirMigratorStub(fileSystemMock, oldUserDirMock, newUserDirMock, MagicMock())
        userDirMigratorStub.migrate()

        self.assertFalse(userDirMigratorStub.moveContentCalled)
        oldUserDirMock.setToCurrentVersion.assert_not_called()
        newUserDirMock.setToCurrentVersion.assert_not_called()



class _UserDirMigratorStub(_UserDirMigratorBase):

    def __init__(self, fileSystem: _FileSystem, oldAppDir: AppDir, newAppDir: AppDir, cmdlineUi: CmdlineUi):
        super().__init__(fileSystem, oldAppDir, newAppDir, cmdlineUi)

        self.moveContentCalled: bool = False
        self.moveContentCalledWith: Sequence[AppDir] = ()



    @property
    def dirName_(self) -> str:
        return "test dir name"



    @override
    def moveContent_(self, oldUserDir: AppDir, newUserDir: AppDir):
        self.moveContentCalled = True
        self.moveContentCalledWith = (oldUserDir, newUserDir)



    def isOldUserDirExisting_(self) -> bool:
        return self.fileSystem_.exists(self.oldUserDir_.path)
