<!-- [DEF:GitSettingsPage:Component] -->
<!--
@SEMANTICS: git, settings, configuration, integration
@PURPOSE:   Manage Git server configurations for dashboard versioning.
@LAYER:     Page
@RELATION:  USES -> gitService
@RELATION:  USES -> Button, Input, Card, PageHeader, Select

@INVARIANT: All configurations must be validated via connection test.
-->

<script lang="ts">
    // [SECTION: IMPORTS]
    import { onMount } from "svelte";
    import { gitService } from "../../../services/gitService";
    import { addToast as toast } from "../../../lib/toasts.js";
    import { t } from "$lib/i18n";
    import { Button, Input, Card, PageHeader, Select } from "$lib/ui";
    // [/SECTION: IMPORTS]

    // [SECTION: STATE]
    let configs = $state([]);
    let newConfig = $state({
        name: "",
        provider: "GITHUB",
        url: "https://github.com",
        pat: "",
        default_repository: "",
        default_branch: "main",
    });
    let isEditing = $state(false);
    let editingConfigId = $state(null);
    let testing = $state(false);
    let selectedGiteaConfigId = $state("");
    let giteaRepos = $state([]);
    let giteaLoading = $state(false);
    let giteaCreating = $state(false);
    let giteaDeleting = $state(false);
    let newGiteaRepo = $state({
        name: "",
        private: true,
        description: "",
        auto_init: true,
        default_branch: "main",
    });
    // [/SECTION: STATE]

    // [DEF:loadConfigs:Function]
    /**
     * @purpose Fetches existing git configurations.
     * @pre Component is mounted.
     * @post configs state is populated.
     */
    async function loadConfigs() {
        try {
            configs = await gitService.getConfigs();
        } catch (e) {
            toast(e.message, "error");
        }
    }
    // [/DEF:loadConfigs:Function]

    onMount(loadConfigs);

    // [DEF:handleTest:Function]
    /**
     * @purpose Tests connection to a git server with current form data.
     * @pre newConfig contains valid provider, url, and pat.
     * @post testing state is managed; toast shown with result.
     */
    async function handleTest() {
        testing = true;
        try {
            const testPayload = { ...newConfig };
            if (isEditing && editingConfigId) {
                testPayload.config_id = editingConfigId;
            }
            const result = await gitService.testConnection(testPayload);
            if (result.status === "success") {
                toast($t.settings?.connection_success, "success");
            } else {
                toast(
                    result.message || $t.settings?.connection_failed_short,
                    "error",
                );
            }
        } catch (e) {
            toast($t.settings?.connection_failed_short, "error");
        } finally {
            testing = false;
        }
    }
    // [/DEF:handleTest:Function]

    // [DEF:handleSave:Function]
    /**
     * @purpose Saves a new git configuration.
     * @pre newConfig is valid and tested.
     * @post New config is saved to DB and added to configs list.
     */
    async function handleSave() {
        try {
            if (isEditing) {
                const updated = await gitService.updateConfig(
                    editingConfigId,
                    newConfig,
                );
                configs = configs.map((c) =>
                    c.id === editingConfigId ? updated : c,
                );
                toast(
                    $t.settings?.git_config_updated ||
                        "Git configuration updated",
                    "success",
                );
            } else {
                const saved = await gitService.createConfig(newConfig);
                configs = [...configs, saved];
                toast(
                    $t.settings?.git_config_saved || "Git configuration saved",
                    "success",
                );
            }
            resetForm();
        } catch (e) {
            toast(e.message, "error");
        }
    }
    // [/DEF:handleSave:Function]

    // [DEF:handleEdit:Function]
    /**
     * @purpose Populates the form with an existing config to edit.
     * @param {Object} config - Configuration object to edit.
     * @post Form is populated and isEditing state is set.
     */
    function handleEdit(config) {
        isEditing = true;
        editingConfigId = config.id;
        newConfig = {
            name: config.name,
            provider: config.provider,
            url: config.url,
            pat: config.pat,
            default_repository: config.default_repository || "",
            default_branch: config.default_branch || "main",
        };
        // Scroll to the form
        window.scrollTo({ top: 0, behavior: "smooth" });
    }
    // [/DEF:handleEdit:Function]

    // [DEF:resetForm:Function]
    /**
     * @purpose Resets the configuration form.
     */
    function resetForm() {
        isEditing = false;
        editingConfigId = null;
        newConfig = {
            name: "",
            provider: "GITHUB",
            url: "https://github.com",
            pat: "",
            default_repository: "",
            default_branch: "main",
        };
    }
    // [/DEF:resetForm:Function]
    // [DEF:handleDelete:Function]
    /**
     * @purpose Deletes a git configuration by ID.
     * @param {string} id - Configuration ID.
     * @pre id is valid; user confirmed deletion.
     * @post Configuration is removed from DB and local state.
     */
    async function handleDelete(id) {
        if (!confirm($t.settings?.git_delete_confirm)) return;
        try {
            await gitService.deleteConfig(id);
            configs = configs.filter((c) => c.id !== id);
            toast($t.settings?.git_config_deleted, "success");
            if (selectedGiteaConfigId === id) {
                selectedGiteaConfigId = "";
                giteaRepos = [];
            }
        } catch (e) {
            toast(e.message, "error");
        }
    }
    // [/DEF:handleDelete:Function]

    // [DEF:loadGiteaRepos:Function]
    /**
     * @purpose Loads repositories from selected Gitea config.
     * @pre selectedGiteaConfigId is set.
     * @post giteaRepos state updated.
     */
    async function loadGiteaRepos() {
        if (!selectedGiteaConfigId) {
            giteaRepos = [];
            return;
        }
        giteaLoading = true;
        try {
            giteaRepos = await gitService.listGiteaRepositories(
                selectedGiteaConfigId,
            );
        } catch (e) {
            toast(e.message, "error");
            giteaRepos = [];
        } finally {
            giteaLoading = false;
        }
    }
    // [/DEF:loadGiteaRepos:Function]

    // [DEF:handleCreateGiteaRepo:Function]
    /**
     * @purpose Creates new repository on selected Gitea server.
     * @pre selectedGiteaConfigId and newGiteaRepo.name are set.
     * @post Repository created and repos list reloaded.
     */
    async function handleCreateGiteaRepo() {
        if (!selectedGiteaConfigId || !newGiteaRepo.name?.trim()) return;
        giteaCreating = true;
        try {
            await gitService.createGiteaRepository(selectedGiteaConfigId, {
                ...newGiteaRepo,
                name: newGiteaRepo.name.trim(),
            });
            toast("Gitea repository created", "success");
            newGiteaRepo = {
                name: "",
                private: true,
                description: "",
                auto_init: true,
                default_branch: "main",
            };
            await loadGiteaRepos();
        } catch (e) {
            toast(e.message, "error");
        } finally {
            giteaCreating = false;
        }
    }
    // [/DEF:handleCreateGiteaRepo:Function]

    // [DEF:handleDeleteGiteaRepo:Function]
    /**
     * @purpose Deletes repository from selected Gitea server.
     * @pre selectedGiteaConfigId is set.
     * @post Repository deleted and repos list reloaded.
     */
    async function handleDeleteGiteaRepo(repo) {
        if (!selectedGiteaConfigId) return;
        if (!confirm(`Delete repository ${repo.full_name || repo.name}?`))
            return;
        const fullName = String(repo.full_name || "");
        const parts = fullName.split("/");
        const owner = parts.length > 1 ? parts[0] : "";
        const repoName = parts.length > 1 ? parts[1] : repo.name;
        if (!owner || !repoName) {
            toast("Cannot resolve repository owner/name", "error");
            return;
        }
        giteaDeleting = true;
        try {
            await gitService.deleteGiteaRepository(
                selectedGiteaConfigId,
                owner,
                repoName,
            );
            toast("Gitea repository deleted", "success");
            await loadGiteaRepos();
        } catch (e) {
            toast(e.message, "error");
        } finally {
            giteaDeleting = false;
        }
    }
    // [/DEF:handleDeleteGiteaRepo:Function]

    $effect(() => {
        if (selectedGiteaConfigId) {
            void loadGiteaRepos();
        }
    });
</script>

<!-- [SECTION: TEMPLATE] -->
<div class="p-6 max-w-6xl mx-auto">
    <PageHeader title={$t.nav?.settings_git} />

    <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
        <!-- List of Configs -->
        <Card title={$t.settings?.configured_servers}>
            {#if configs.length === 0}
                <p class="text-gray-500">{$t.git?.no_servers_configured}</p>
            {:else}
                <ul class="divide-y divide-gray-100">
                    {#each configs as config}
                        <li class="py-4 flex justify-between items-center">
                            <div>
                                <div class="flex items-center gap-2">
                                    <span class="font-medium text-gray-900"
                                        >{config.name}</span
                                    >
                                    <span
                                        class="text-xs font-mono bg-gray-50 text-gray-500 px-1.5 py-0.5 rounded"
                                        >{config.provider}</span
                                    >
                                </div>
                                <div class="text-xs text-gray-400 mt-1">
                                    {config.url}
                                </div>
                            </div>
                            <div class="flex items-center space-x-4">
                                <span
                                    class="px-2 py-1 text-xs font-medium rounded {config.status ===
                                    'CONNECTED'
                                        ? 'bg-green-50 text-green-700'
                                        : 'bg-red-50 text-red-700'}"
                                >
                                    {config.status}
                                </span>
                                <button
                                    onclick={() => handleEdit(config)}
                                    class="text-gray-400 hover:text-blue-600 transition-colors"
                                    title={$t.common?.edit || "Edit"}
                                >
                                    <svg
                                        xmlns="http://www.w3.org/2000/svg"
                                        class="h-5 w-5"
                                        viewBox="0 0 20 20"
                                        fill="currentColor"
                                    >
                                        <path
                                            d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"
                                        />
                                    </svg>
                                </button>
                                <button
                                    onclick={() => handleDelete(config.id)}
                                    class="text-gray-400 hover:text-red-600 transition-colors"
                                    title={$t.common?.delete}
                                >
                                    <svg
                                        xmlns="http://www.w3.org/2000/svg"
                                        class="h-5 w-5"
                                        viewBox="0 0 20 20"
                                        fill="currentColor"
                                    >
                                        <path
                                            fill-rule="evenodd"
                                            d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z"
                                            clip-rule="evenodd"
                                        />
                                    </svg>
                                </button>
                            </div>
                        </li>
                    {/each}
                </ul>
            {/if}
        </Card>

        <!-- Add/Edit Config -->
        <Card
            title={isEditing
                ? $t.settings?.edit_git_server || "Edit Git server"
                : $t.settings?.add_git_server}
        >
            <div class="space-y-6">
                <Input
                    label={$t.settings?.display_name}
                    bind:value={newConfig.name}
                    placeholder={$t.settings?.display_name_placeholder}
                />
                <Select
                    label={$t.llm?.type}
                    bind:value={newConfig.provider}
                    options={[
                        { value: "GITHUB", label: "GitHub" },
                        { value: "GITLAB", label: "GitLab" },
                        { value: "GITEA", label: "Gitea" },
                    ]}
                />
                <Input
                    label={$t.settings?.server_url}
                    bind:value={newConfig.url}
                />
                <Input
                    label={$t.settings?.personal_access_token}
                    type="password"
                    bind:value={newConfig.pat}
                />
                <Input
                    label={$t.settings?.default_repository_optional}
                    bind:value={newConfig.default_repository}
                    placeholder="org/repo"
                />
                <Input
                    label={$t.settings?.default_branch ||
                        "Логика / ветка по умолчанию"}
                    bind:value={newConfig.default_branch}
                    placeholder="main"
                />

                <div class="flex gap-3 pt-2">
                    <Button
                        variant="secondary"
                        onclick={handleTest}
                        isLoading={testing}
                    >
                        {$t.llm?.test}
                    </Button>
                    <Button variant="primary" onclick={handleSave}>
                        {isEditing
                            ? $t.settings?.update_configuration ||
                              "Update configuration"
                            : $t.settings?.save_configuration}
                    </Button>
                    {#if isEditing}
                        <Button variant="secondary" onclick={resetForm}>
                            {$t.common?.cancel || "Cancel"}
                        </Button>
                    {/if}
                </div>
            </div>
        </Card>
    </div>

    <div class="mt-8">
        <Card title="Gitea repositories">
            <div class="space-y-4">
                <Select
                    label="Gitea server config"
                    bind:value={selectedGiteaConfigId}
                    options={[
                        { value: "", label: "Select config" },
                        ...configs
                            .filter((config) => config.provider === "GITEA")
                            .map((config) => ({
                                value: config.id,
                                label: `${config.name} (${config.url})`,
                            })),
                    ]}
                />

                {#if selectedGiteaConfigId}
                    <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
                        <Input
                            label="Repository name"
                            bind:value={newGiteaRepo.name}
                            placeholder="dashboard-configs"
                        />
                        <Input
                            label="Default branch"
                            bind:value={newGiteaRepo.default_branch}
                            placeholder="main"
                        />
                        <Input
                            class="md:col-span-2"
                            label="Description"
                            bind:value={newGiteaRepo.description}
                            placeholder="Repository for Superset dashboards"
                        />
                    </div>
                    <div class="flex gap-3">
                        <Button
                            variant="primary"
                            onclick={handleCreateGiteaRepo}
                            isLoading={giteaCreating}
                            disabled={!newGiteaRepo.name.trim()}
                        >
                            Create repository
                        </Button>
                        <Button
                            variant="secondary"
                            onclick={loadGiteaRepos}
                            isLoading={giteaLoading}
                        >
                            Reload repositories
                        </Button>
                    </div>

                    {#if giteaRepos.length === 0 && !giteaLoading}
                        <p class="text-sm text-gray-500">
                            No repositories found for this Gitea user.
                        </p>
                    {:else}
                        <div
                            class="divide-y divide-gray-100 border border-gray-200 rounded-lg"
                        >
                            {#each giteaRepos as repo}
                                <div
                                    class="p-3 flex items-center justify-between gap-4"
                                >
                                    <div class="min-w-0">
                                        <div
                                            class="font-medium text-gray-900 truncate"
                                        >
                                            {repo.full_name || repo.name}
                                        </div>
                                        <div
                                            class="text-xs text-gray-500 truncate"
                                        >
                                            {repo.clone_url || repo.html_url}
                                        </div>
                                    </div>
                                    <Button
                                        variant="danger"
                                        size="sm"
                                        onclick={() =>
                                            handleDeleteGiteaRepo(repo)}
                                        disabled={giteaDeleting}
                                    >
                                        Delete
                                    </Button>
                                </div>
                            {/each}
                        </div>
                    {/if}
                {/if}
            </div>
        </Card>
    </div>
</div>
<!-- [/SECTION: TEMPLATE] -->

<!-- [/DEF:GitSettingsPage:Component] -->
