import * as dntShim from "../../../_dnt.shims.js";
import { colors, log, yamlStringify } from "../../../deps.js";
import { requireLogin } from "../../core/auth.js";
import { resolveWorkspace } from "../../core/context.js";
import * as wmill from "../../../gen/services.gen.js";
import { readConfigFile, getEffectiveSettings, DEFAULT_SYNC_OPTIONS, getWmillYamlPath } from "../../core/conf.js";
import { deepEqual } from "../../utils/utils.js";
import { getCurrentGitBranch, isGitRepository } from "../../utils/git.js";
import { GitSyncSettingsConverter } from "./converter.js";
import { handleLegacyRepositoryMigration } from "./legacySettings.js";
import { selectAndLogRepository, generateStructuredDiff, generateChanges, displayChanges, applyBackendSettingsToBranch, normalizeRepoPath, outputResult } from "./utils.js";
export async function pullGitSyncSettings(opts) {
    const workspace = await resolveWorkspace(opts);
    await requireLogin(opts);
    try {
        // Parse and validate --with-backend-settings if provided
        let settings;
        if (opts.withBackendSettings) {
            try {
                const parsedSettings = JSON.parse(opts.withBackendSettings);
                // Validate the structure matches expected format (raw settings object)
                if (!parsedSettings.include_path ||
                    !Array.isArray(parsedSettings.include_path)) {
                    throw new Error("Invalid settings format. Expected include_path array");
                }
                if (!parsedSettings.include_type ||
                    !Array.isArray(parsedSettings.include_type)) {
                    throw new Error("Invalid settings format. Expected include_type array");
                }
                // Create mock backend response with single repository using provided settings
                const mockRepositoryPath = opts.repository || "u/mock/repo";
                settings = {
                    git_sync: {
                        repositories: [{
                                git_repo_resource_path: mockRepositoryPath,
                                settings: {
                                    include_path: parsedSettings.include_path,
                                    include_type: parsedSettings.include_type,
                                    exclude_path: parsedSettings.exclude_path || [],
                                    extra_include_path: parsedSettings.extra_include_path || [],
                                },
                            }],
                    },
                };
            }
            catch (parseError) {
                const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
                outputResult(opts, {
                    success: false,
                    error: `Failed to parse --with-backend-settings JSON: ${errorMessage}`,
                });
                return;
            }
        }
        else {
            // Fetch workspace settings to get git-sync configuration
            try {
                settings = await wmill.getSettings({
                    workspace: workspace.workspaceId,
                });
            }
            catch (apiError) {
                const errorMessage = apiError instanceof Error ? apiError.message : String(apiError);
                outputResult(opts, {
                    success: false,
                    error: `Failed to fetch workspace settings: ${errorMessage}`,
                });
                return;
            }
        }
        if (!settings.git_sync?.repositories ||
            settings.git_sync.repositories.length === 0) {
            outputResult(opts, {
                success: false,
                error: "No git-sync repositories configured",
            });
            return;
        }
        // Find the repository to work with
        let selectedRepo = await selectAndLogRepository(settings.git_sync.repositories, opts.repository, opts.jsonOutput);
        // Check if the selected repository needs migration and handle it
        selectedRepo = await handleLegacyRepositoryMigration(selectedRepo, settings.git_sync, workspace, opts, "pull");
        // Convert backend settings to SyncOptions format
        const backendSyncOptions = GitSyncSettingsConverter.fromBackendFormat(selectedRepo.settings);
        // Check if wmill.yaml exists - create a default one if it doesn't exist
        const wmillYamlPath = getWmillYamlPath();
        const wmillYamlExists = wmillYamlPath !== null;
        if (!wmillYamlExists) {
            if (!opts.jsonOutput) {
                log.info(colors.yellow("No wmill.yaml file found. Will create one with backend git-sync settings."));
            }
        }
        let localConfig;
        if (wmillYamlExists) {
            localConfig = await readConfigFile();
        }
        else {
            localConfig = { ...DEFAULT_SYNC_OPTIONS };
        }
        // Handle the case where wmill.yaml doesn't exist - just create it with backend settings
        if (!wmillYamlExists) {
            // When creating from scratch, just apply backend settings directly
            let updatedConfig = { ...localConfig };
            // Apply backend settings to the default config
            Object.assign(updatedConfig, backendSyncOptions);
            // Add git branch structure if in a git repository
            if (isGitRepository()) {
                const currentBranch = getCurrentGitBranch();
                if (currentBranch) {
                    if (!updatedConfig.gitBranches) {
                        updatedConfig.gitBranches = {};
                    }
                    if (!updatedConfig.gitBranches[currentBranch]) {
                        updatedConfig.gitBranches[currentBranch] = { overrides: {} };
                    }
                }
            }
            // Write the new configuration
            await dntShim.Deno.writeTextFile("wmill.yaml", yamlStringify(updatedConfig));
            if (opts.jsonOutput) {
                console.log(JSON.stringify({
                    success: true,
                    message: "wmill.yaml created with backend git-sync settings",
                    repository: selectedRepo.git_repo_resource_path,
                }));
            }
            else {
                log.info(colors.green(`wmill.yaml created with git-sync settings from ${selectedRepo.git_repo_resource_path}`));
            }
            return;
        }
        // For existing wmill.yaml files, continue with the normal flow
        // Calculate current settings once and reuse throughout
        const currentSettings = await getEffectiveSettings(localConfig, opts.promotion, true, opts.jsonOutput);
        // Determine write mode for branch-based configuration
        let writeMode = "replace";
        // Determine write mode based on flags
        if (opts.default || opts.replace) {
            writeMode = "replace";
        }
        else if (opts.override) {
            writeMode = "override";
        }
        else {
            // Default behavior for existing files with no explicit flags
            // Use same logic as diff to determine if there's a real conflict
            const gitSyncBackend = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(backendSyncOptions));
            const gitSyncCurrent = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(currentSettings));
            const hasConflict = !deepEqual(gitSyncBackend, gitSyncCurrent);
            if (hasConflict) {
                // For diff mode, show what override would look like
                writeMode = "override";
            }
            else {
                writeMode = "replace";
            }
        }
        if (opts.diff) {
            // Show differences between local and backend
            const normalizedCurrent = GitSyncSettingsConverter.normalize(currentSettings);
            const normalizedBackend = GitSyncSettingsConverter.normalize(backendSyncOptions);
            const gitSyncCurrent = GitSyncSettingsConverter.extractGitSyncFields(normalizedCurrent);
            const gitSyncBackend = GitSyncSettingsConverter.extractGitSyncFields(normalizedBackend);
            const hasChanges = !deepEqual(gitSyncBackend, gitSyncCurrent);
            if (opts.jsonOutput) {
                const repoPath = normalizeRepoPath(selectedRepo.git_repo_resource_path);
                // Generate structured diff using the same normalized objects
                const structuredDiff = hasChanges
                    ? generateStructuredDiff(gitSyncCurrent, gitSyncBackend)
                    : {};
                console.log(JSON.stringify({
                    success: true,
                    hasChanges,
                    local: GitSyncSettingsConverter.toBackendFormat(normalizedCurrent),
                    backend: GitSyncSettingsConverter.toBackendFormat(normalizedBackend),
                    repository: selectedRepo.git_repo_resource_path,
                    diff: structuredDiff,
                }));
            }
            else {
                if (hasChanges) {
                    log.info("Changes that would be applied locally:");
                    const changes = generateChanges(currentSettings, backendSyncOptions);
                    if (Object.keys(changes).length === 0) {
                        log.info(colors.green("No differences found"));
                    }
                    else {
                        displayChanges(changes);
                    }
                }
                else {
                    log.info(colors.green("No differences found"));
                }
            }
            return;
        }
        // For non-diff mode, handle interactive logic if needed
        // Only show interactive prompts for existing files with conflicts
        if (!opts.diff &&
            !opts.default &&
            !opts.replace &&
            !opts.override) {
            // Recalculate current settings with promotion if needed
            const effectiveCurrentSettings = await getEffectiveSettings(localConfig, opts.promotion, true, opts.jsonOutput);
            // Use the same logic as diff to determine current settings
            const gitSyncBackend = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(backendSyncOptions));
            const gitSyncCurrent = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(effectiveCurrentSettings));
            const hasConflict = !deepEqual(gitSyncBackend, gitSyncCurrent);
            if (hasConflict && !opts.yes && dntShim.Deno.stdin.isTerminal()) {
                // Show the diff first
                log.info("Changes that would be applied locally:");
                const changes = generateChanges(effectiveCurrentSettings, backendSyncOptions);
                if (Object.keys(changes).length > 0) {
                    displayChanges(changes);
                }
                // Interactive mode - ask user
                const { Select } = await import("../../../deps.js");
                const choice = await Select.prompt({
                    message: "Settings conflict detected. How would you like to proceed?",
                    options: [
                        {
                            name: "Replace existing settings",
                            value: "replace",
                        },
                        {
                            name: "Add branch-specific override",
                            value: "override",
                        },
                        { name: "Cancel", value: "cancel" },
                    ],
                });
                if (choice === "cancel") {
                    log.info("Operation cancelled");
                    return;
                }
                writeMode = choice;
            }
            else if (hasConflict && opts.yes) {
                // --yes flag: default to override behavior for conflicts
                writeMode = "override";
                log.info(colors.yellow("Settings conflict detected. Using --override behavior (default for --yes)."));
            }
            else if (hasConflict) {
                // Non-interactive mode with conflicts - show message and exit
                if (opts.jsonOutput) {
                    console.log(JSON.stringify({
                        success: false,
                        error: "Settings conflict detected. Use --replace or --override flags to resolve.",
                        hasConflict: true,
                    }));
                }
                else {
                    log.error(colors.red("Settings conflict detected."));
                    log.info("Use --replace to overwrite existing settings or --override to add branch-specific override.");
                }
                return;
            }
        }
        // Check if there are actually any changes before writing
        const gitSyncBackend = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(backendSyncOptions));
        const gitSyncCurrent = GitSyncSettingsConverter.extractGitSyncFields(GitSyncSettingsConverter.normalize(currentSettings));
        const hasActualChanges = !deepEqual(gitSyncBackend, gitSyncCurrent);
        if (!hasActualChanges && wmillYamlExists) {
            // Even if no changes, check if we need to create empty branch structure
            let needsBranchStructure = false;
            if (isGitRepository()) {
                const currentBranch = getCurrentGitBranch();
                if (currentBranch && (!localConfig.gitBranches || !localConfig.gitBranches[currentBranch])) {
                    needsBranchStructure = true;
                    // Create empty branch structure
                    const updatedConfig = { ...localConfig };
                    if (!updatedConfig.gitBranches) {
                        updatedConfig.gitBranches = {};
                    }
                    if (!updatedConfig.gitBranches[currentBranch]) {
                        updatedConfig.gitBranches[currentBranch] = { overrides: {} };
                    }
                    // Write updated configuration
                    await dntShim.Deno.writeTextFile("wmill.yaml", yamlStringify(updatedConfig));
                    if (opts.jsonOutput) {
                        console.log(JSON.stringify({
                            success: true,
                            message: `Created empty branch structure for: ${currentBranch}`,
                            repository: selectedRepo.git_repo_resource_path,
                        }));
                    }
                    else {
                        log.info(colors.green(`Created empty branch structure for: ${currentBranch}`));
                    }
                    return;
                }
            }
            if (opts.jsonOutput) {
                console.log(JSON.stringify({
                    success: true,
                    message: "No changes needed",
                    repository: selectedRepo.git_repo_resource_path,
                }));
            }
            else {
                log.info(colors.green("No changes needed - settings are already up to date"));
            }
            return;
        }
        // Apply the settings based on write mode
        let updatedConfig;
        if (writeMode === "replace") {
            // Replace top-level settings
            updatedConfig = { ...localConfig };
            // Update with backend git-sync settings
            Object.assign(updatedConfig, backendSyncOptions);
        }
        else {
            // Override mode - will be handled by branch logic below
            updatedConfig = { ...localConfig };
        }
        // For replace mode, add empty branch structure if in Git repo
        if (writeMode === "replace" && isGitRepository()) {
            const currentBranch = getCurrentGitBranch();
            if (currentBranch) {
                log.info(`Detected Git repository, adding empty branch structure for: ${currentBranch}`);
                if (!updatedConfig.gitBranches) {
                    updatedConfig.gitBranches = {};
                }
                if (!updatedConfig.gitBranches[currentBranch]) {
                    updatedConfig.gitBranches[currentBranch] = { overrides: {} };
                }
            }
        }
        // For override mode, write to branch overrides
        if (writeMode === "override" && isGitRepository()) {
            const currentBranch = getCurrentGitBranch();
            if (currentBranch) {
                log.info(`Detected Git repository, writing settings to branch: ${currentBranch}`);
                updatedConfig = applyBackendSettingsToBranch(localConfig, currentBranch, backendSyncOptions);
            }
        }
        // Write updated configuration
        await dntShim.Deno.writeTextFile("wmill.yaml", yamlStringify(updatedConfig));
        if (opts.jsonOutput) {
            console.log(JSON.stringify({
                success: true,
                message: `Git-sync settings pulled successfully`,
                repository: selectedRepo.git_repo_resource_path,
            }));
        }
        else {
            log.info(colors.green(`Git-sync settings pulled successfully from ${selectedRepo.git_repo_resource_path}`));
            if (writeMode === "override") {
                const currentBranch = getCurrentGitBranch();
                if (currentBranch) {
                    log.info(colors.gray(`Settings written to branch '${currentBranch}' overrides`));
                }
            }
            else if (writeMode === "replace") {
                log.info(colors.gray(`Settings written to top-level configuration`));
            }
        }
    }
    catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        if (opts.jsonOutput) {
            console.log(JSON.stringify({ success: false, error: errorMessage }));
        }
        else {
            log.error(colors.red(`Failed to pull git-sync settings: ${errorMessage}`));
        }
    }
}
