<?php namespace App\Libraries;

use Exception;

class UpdatesManager
{
    private GitHub $github;
    private Settings $settings;

    /**
     * Create models, config and library's
     */
    function __construct()
    {
        $this->github = new GitHub();
        $this->settings = new Settings();
    }

    /**************************************************************************************
     * PUBLIC FUNCTIONS
     **************************************************************************************/

    /**
     * Get installed version
     * @return array
     */
    public function get_installed_version(): array
    {
        try {
            // Get compatibility date from local version file
            $coreVersion = $this->get_core_version();
            if (!$coreVersion['event']) {
                return ['event' => false, 'message' => $coreVersion['message']];
            }
            $coreDate = $coreVersion['data']['compatibility_date'];

            // Get compatibility date from settings
            $dbVersion = $this->get_db_version();
            if (!$dbVersion['event']) {
                return ['event' => false, 'message' => $dbVersion['message']];
            }
            $dbDate = $dbVersion['data']['compatibility_date'];

            // Get compatibility date from repository
            $repoVersion = $this->github->get_repo_version($this->settings->get_config("github_branch"));
            $repoDate = $repoVersion['event'] ? $repoVersion['data']['compatibility_date'] : '';

            return ['event' => true, 'data' => [
                'compatibility_date' => $coreDate,
                'db_updates_installed' => $coreDate === $dbDate,
                'repo_updates_installed' => $coreDate === $repoDate,
                'release_notes' => $coreVersion['data']['release_notes'],
                'version' => $coreVersion['data']['version'],
            ]];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_106")];
        }
    }
    
    /**
     * Check if installed version is correct
     * @return array
     */
    public function check_installation(): array
    {
        try {
            $version = $this->get_installed_version();
            if (!$version['event'] || !$version['data']) {
                return ['event' => false, 'message' => $version['message']];
            }

            if (!$version['data']['db_updates_installed'] || !$version['data']['repo_updates_installed']) {
                return ['event' => false, 'message' => lang("Message.message_103")];
            }

            return ['event' => true];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_106")];
        }
    }

    /**
     * Check and update selected branch
     * @return array
     */
    public function check_prepare_branch(string $branch): array
    {
        try {
            $repoVersion = $this->github->get_repo_version($this->settings->get_config("github_branch"));
            if (!$repoVersion['event']) {
                return ['event' => false, 'message' => $repoVersion['message']];
            }
            $repoDate = $repoVersion['data']['compatibility_date'];

            $targetBranchVersion = $this->github->get_repo_version($branch);

            if (!$targetBranchVersion['event'] || $repoDate !== $targetBranchVersion['data']['compatibility_date']) {
                $cleanResult = $this->clean_old_files($branch);
                if (!$cleanResult['event']) {
                    return ['event' => false, 'message' => $cleanResult['message']];
                }

                // Need to update the target branch
                $mergeResult = $this->github->create_merge_commit($this->settings->get_config("github_branch"), $branch);
                if (!$mergeResult['event']) {
                    return ['event' => false, 'message' => $mergeResult['message']];
                }
            }

            return ['event' => true];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_111")];
        }
    }

    /**
     * Install repository updates by setting up and triggering GitHub action
     * @return array
     */
    public function install_repo_updates(): array
    {
        try {
            // Check if the core is compatible with the template repository
            $coreVersion = $this->get_core_version();
            if (!$coreVersion['event']) {
                return ['event' => false, 'message' => $coreVersion['message']];
            }
            $coreDate = $coreVersion['data']['compatibility_date'];

            $templateVersion = $this->github->get_template_version();
            if (!$templateVersion['event']) {
                return ['event' => false, 'message' => $templateVersion['message']];
            }
            $templateDate = $templateVersion['data']['compatibility_date'];

            if ($coreDate !== $templateDate) {
                return ['event' => false, 'message' => lang("Message.message_110")];
            }

            // Set up the repo by uploading the GitHub action file
            $setupResult = $this->set_up_repo();
            if (!$setupResult['event']) {
                return ['event' => false, 'message' => $setupResult['message']];
            }

            // Wait for 5 seconds to ensure the files are uploaded
            sleep(5);

            // Clean up old files
            $cleanResult = $this->clean_old_files($this->settings->get_config("github_branch"));
            if (!$cleanResult['event']) {
                return ['event' => false, 'message' => $cleanResult['message']];
            }

            // Trigger the update-repo action
            $triggerResult = $this->github->trigger_action(
                'update-repo.yml',
                $this->settings->get_config("github_branch"),
                ['github_token'=> $this->settings->get_config('github_token')]
            );

            return $triggerResult;
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_109")];
        }
    }

    /**
     * Get status of repository update process
     * @return array
     */
    public function get_repo_update_status(): array
    {
        try {
            $result = $this->github->get_last_action('update-repo.yml', $this->settings->get_config("github_branch"));
            return $result;
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_109")];
        }
    }

    /**************************************************************************************
     * PRIVATE FUNCTIONS
     **************************************************************************************/

    /**
     * Commit update-repo.yml file to the main branch
     * @return array
     */
    private function set_up_repo(): array
    {
        try {
            $fullPath = WRITEPATH . 'updates/workflows/update-repo.yml';
            $repoPath = '.github/workflows/update-repo.yml';

            if (!file_exists($fullPath)) {
                return ['event' => false, 'message' => lang("Message.message_107")];
            }

            $content = file_get_contents($fullPath);
            return $this->github->create_commit($this->settings->get_config("github_branch"), $repoPath, $content);
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_108")];
        }
    }

    /** 
     * Clean up old files that are no longer needed
     * @param string $branchName The branch name to delete files from
     * @return array Status of the operation
     */
    private function clean_old_files(string $branchName): array
    {
        try {
            // List of files to be deleted
            $filesToDelete = [
                'android/app/build.gradle',
                'android/app/build.gradle.kts',
                'android/build.gradle',
                'android/settings.gradle'
            ];
            
            // Delete each file and return on first error
            foreach ($filesToDelete as $filePath) {
                $result = $this->github->delete_file($branchName, $filePath, true);
                if (!$result['event']) {
                    return ['event' => false, 'message' => $result['message']];
                }
            }
            
            return ['event' => true];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_109")];
        }
    }

    /**
     * Get core version
     * @return array
     */
    private function get_core_version(): array
    {
        try {
            $localVersionPath = WRITEPATH . 'version.json';
            if (!file_exists($localVersionPath)) {
                return ['event' => false, 'message' => lang("Message.message_104")];
            }

            $localVersion = json_decode(file_get_contents($localVersionPath), true);
            return ['event' => true, 'data' => $localVersion];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_106")];
        }
    }

    /**
     * Get database version
     * @return array
     */
    private function get_db_version(): array
    {
        try {
            $dbVersion = $this->settings->get_config("compatibility_date");
            return ['event' => true, 'data' => ['compatibility_date' => $dbVersion]];
        } catch (Exception $e) {
            return ['event' => false, 'message' => lang("Message.message_106")];
        }
    }
}
