import { Setting, App, Plugin, TextComponent } from "obsidian";

import { DOCUMENTATION_URLS } from "../../constants";
import { ModelRegistry } from "../../services/ModelRegistry";
import { hasGoogleApiKey } from "../../utils/secrets";
import { FolderSuggest } from "../../views/FolderSuggest";
import { renderModelDropdown } from "../components";
import { SettingsTabContext } from "../SettingsTabContext";
import { IVaultIntelligencePlugin, DEFAULT_SETTINGS, DEFAULT_GARDENER_SYSTEM_PROMPT } from "../types";

interface InternalApp extends App {
    setting: {
        openTabById: (id: string) => void;
    };
}

export function renderGardenerSettings(context: SettingsTabContext): void {
    const { containerEl, plugin } = context;
    const gardener = "Gardener";
    const gemini = "Gemini";
    const ontology = "Ontology";
    const archive = "Archive";

    containerEl.createDiv({ cls: 'vault-intelligence-settings-subheading' }, (div) => {
        div.createSpan({ text: `Configure the ${gardener.toLowerCase()} to maintain your vault’s ontology and hygiene. ` });
        div.createEl('a', {
            attr: { href: DOCUMENTATION_URLS.SECTIONS.GARDENER, target: '_blank' },
            text: 'View documentation'
        });
    });

    const hasApiKey = hasGoogleApiKey(plugin.settings);
    const hasOllama = !!plugin.settings.ollamaEndpoint;
    const canUseChat = hasApiKey || hasOllama;


    // --- 1. Model & Limits ---
    const gardenerModelCurrent = plugin.settings.gardenerModel;
    const chatModels = ModelRegistry.getChatModels(plugin.settings.hiddenModels);
    const isGardenerPreset = chatModels.some(m => m.id === gardenerModelCurrent);

    new Setting(containerEl)
        .setName(`${gardener} model`)
        .setDesc('The model used for analysis and suggesting improvements.')
        .addDropdown(dropdown => {
            renderModelDropdown(dropdown, chatModels, gardenerModelCurrent, canUseChat, hasOllama, (val) => {
                void (async () => {
                    if (val !== 'custom') {
                        plugin.settings.gardenerModel = val;
                        await plugin.saveSettings();
                    }
                    refreshSettings(plugin);
                })();
            });
        });

    if (canUseChat && !isGardenerPreset) {
        new Setting(containerEl)
            .setName(`Custom ${gardener.toLowerCase()} model`)
            .setDesc(`Enter the specific ${gemini} model ID.`)
            .addText(text => text
                .setPlaceholder(DEFAULT_SETTINGS.gardenerModel)
                .setValue(gardenerModelCurrent)
                .onChange((value) => {
                    void (async () => {
                        plugin.settings.gardenerModel = value;
                        await plugin.saveSettings();
                    })();
                }));
    }

    const currentModelId = plugin.settings.gardenerModel;
    const gardenerModelLimit = ModelRegistry.getModelById(currentModelId)?.inputTokenLimit ?? 1048576;
    const hasOverride = currentModelId in plugin.settings.modelContextOverrides;
    const resolvedBudget = ModelRegistry.resolveContextBudget(currentModelId, plugin.settings.modelContextOverrides, plugin.settings.gardenerContextBudget);
    
    const displayValue = Math.min(resolvedBudget, gardenerModelLimit);

    new Setting(containerEl)
        .setName("Context budget (tokens)")
        .setDesc(hasOverride 
            ? `Max tokens allowed for a single analysis. Currently overridden for **${currentModelId}**. (Model limit: ${gardenerModelLimit.toLocaleString()} tokens)` 
            : `Max tokens allowed for a single analysis. Currently using provider default. (Model limit: ${gardenerModelLimit.toLocaleString()} tokens)`
        )
        .addExtraButton(btn => btn
            .setIcon('reset')
            .setTooltip(`Reset to provider default`)
            .onClick(() => {
                void (async () => {
                    delete plugin.settings.modelContextOverrides[currentModelId];
                    await plugin.saveSettings();
                    refreshSettings(plugin);
                })();
            }))
        .addText(text => {
            text.setPlaceholder('50000')
                .setValue(String(displayValue))
                .onChange((value) => {
                    void (async () => {
                        let num = parseInt(value);
                        if (!isNaN(num) && num > 0) {
                            if (num > gardenerModelLimit) {
                                num = gardenerModelLimit;
                                text.setValue(String(num));
                            }
                            plugin.settings.modelContextOverrides[currentModelId] = Math.floor(num);
                            await plugin.saveSettings();
                        }
                    })();
                });
            text.inputEl.type = 'number';
        });

    // --- 2. System Instruction ---
    new Setting(containerEl)
        .setName(`${gardener} rules`)
        .setDesc('The base persona and hygiene rules. Use {{ONTOLOGY_FOLDERS}} and {{NOTE_COUNT}} as placeholders.')
        .setClass('vault-intelligence-system-instruction-setting')
        .addExtraButton(btn => btn
            .setIcon('reset')
            .setTooltip("Restore original rules (auto-updates with plugin)")
            .setDisabled(plugin.settings.gardenerSystemInstruction === null)
            .setIcon('reset')
            .setTooltip("Restore original rules (auto-updates with plugin)")
            .setDisabled(plugin.settings.gardenerSystemInstruction === null)
            .onClick(() => {
                void (async () => {
                    plugin.settings.gardenerSystemInstruction = null;
                    await plugin.saveSettings();
                    refreshSettings(plugin);
                })();
            }))
        .addTextArea(text => {
            text.setPlaceholder(DEFAULT_GARDENER_SYSTEM_PROMPT)
                .setValue(plugin.settings.gardenerSystemInstruction || "")
                .onChange((value) => {
                    void (async () => {
                        plugin.settings.gardenerSystemInstruction = value.trim() === "" ? null : value;
                        await plugin.saveSettings();
                    })();
                });
            text.inputEl.rows = 10;
        });

    // --- 3. Paths & Retention ---
    new Setting(containerEl).setName('Paths and retention').setHeading();

    new Setting(containerEl)
        .setName('Ontology path')
        .setDesc('Folder where concepts, entities, and MOCs are stored.')
        .addText(text => {
            text.setPlaceholder(ontology)
                .setValue(plugin.settings.ontologyPath)
                .onChange((value) => {
                    void (async () => {
                        plugin.settings.ontologyPath = value;
                        await plugin.saveSettings();
                    })();
                });
            new FolderSuggest(plugin.app, text.inputEl);
        });

    new Setting(containerEl)
        .setName(`${gardener} plans path`)
        .setDesc(`Folder where proposed ${gardener.toLowerCase()} plans are saved.`)
        .addText(text => {
            text.setPlaceholder(`${gardener}/plans`)
                .setValue(plugin.settings.gardenerPlansPath)
                .onChange((value) => {
                    void (async () => {
                        plugin.settings.gardenerPlansPath = value;
                        await plugin.saveSettings();
                    })();
                });
            new FolderSuggest(plugin.app, text.inputEl);
        });

    new Setting(containerEl)
        .setName("Plans retention (days)")
        .setDesc('Duration to keep plan files before purging.')
        .addText(text => text
            .setPlaceholder('7')
            .setValue(String(plugin.settings.plansRetentionDays))
            .onChange((value) => {
                void (async () => {
                    const num = parseInt(value);
                    if (!isNaN(num) && num >= 0) {
                        plugin.settings.plansRetentionDays = Math.floor(num);
                        await plugin.saveSettings();
                    }
                })();
            }));

    new Setting(containerEl).setName('Orphan management').setHeading();

    new Setting(containerEl)
        .setName('Archive folder path')
        .setDesc(`Where to move notes that are pruned or deleted by the ${gardener}.`)
        .addText(text => {
            text.setPlaceholder(`${ontology}/_${archive}`)
                .setValue(plugin.settings.gardenerArchiveFolderPath)
                .onChange(async (value) => {
                    plugin.settings.gardenerArchiveFolderPath = value;
                    await plugin.saveSettings();
                });
            new FolderSuggest(plugin.app, text.inputEl);
        });

    new Setting(containerEl)
        .setName("Orphan grace period (days)")
        .setDesc(`Number of days a note must be unlinked/orphaned before the ${gardener} suggests pruning it.`)
        .addText(text => text
            .setPlaceholder('7')
            .setValue(String(plugin.settings.gardenerOrphanGracePeriodDays))
            .onChange(async (value) => {
                const num = parseInt(value);
                if (!isNaN(num) && num >= 0) {
                    plugin.settings.gardenerOrphanGracePeriodDays = Math.floor(num);
                    await plugin.saveSettings();
                }
            }));

    // --- 4. Exclusions ---
    new Setting(containerEl).setName('Exclusions').setHeading();

    const excludedFoldersEl = containerEl.createDiv();
    const renderExcludedFolders = () => {
        excludedFoldersEl.empty();
        if (plugin.settings.gardenerExcludedFolders.length === 0) {
            excludedFoldersEl.createEl('i', { text: 'No folders excluded.' });
        }
        plugin.settings.gardenerExcludedFolders.forEach((folder, index) => {
            new Setting(excludedFoldersEl)
                .setName(folder)
                .addExtraButton(btn => btn
                    .setIcon('trash')
                    .setTooltip('Remove')
                    .setIcon('trash')
                    .setTooltip('Remove')
                    .onClick(() => {
                        void (async () => {
                            plugin.settings.gardenerExcludedFolders.splice(index, 1);
                            await plugin.saveSettings();
                            renderExcludedFolders();
                        })();
                    }));
        });
    };
    renderExcludedFolders();

    let addFolderText: TextComponent;
    new Setting(containerEl)
        .setName('Add excluded folder')
        .setDesc('Search for a folder to ignore.')
        .addText(text => {
            addFolderText = text;
            text.setPlaceholder('Search...')
            new FolderSuggest(plugin.app, text.inputEl);
            text.inputEl.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') {
                    void (async () => {
                        const value = text.getValue().trim();
                        if (value && !plugin.settings.gardenerExcludedFolders.includes(value)) {
                            plugin.settings.gardenerExcludedFolders.push(value);
                            await plugin.saveSettings();
                            text.setValue('');
                            renderExcludedFolders();
                        }
                    })();
                }
            });
        })
        .addExtraButton(btn => btn
            .setIcon('plus-with-circle')
            .onClick(() => {
                void (async () => {
                    const value = addFolderText.getValue().trim();
                    if (value && !plugin.settings.gardenerExcludedFolders.includes(value)) {
                        plugin.settings.gardenerExcludedFolders.push(value);
                        await plugin.saveSettings();
                        addFolderText.setValue('');
                        renderExcludedFolders();
                    }
                })();
            }));

    // --- 5. Advanced Tuning ---
    new Setting(containerEl).setName('Analysis tuning').setHeading();

    new Setting(containerEl)
        .setName("Recent note limit")
        .setDesc('Max number of recent notes to scan for improvements.')
        .addText(text => text
            .setPlaceholder('10')
            .setValue(String(plugin.settings.gardenerNoteLimit))
            .onChange((value) => {
                void (async () => {
                    const num = parseInt(value);
                    if (!isNaN(num) && num >= 0) {
                        plugin.settings.gardenerNoteLimit = Math.floor(num);
                        await plugin.saveSettings();
                    }
                })();
            }));

    new Setting(containerEl)
        .setName("Re-check cooldown (days)")
        .setDesc('Wait duration before re-examining unchanged files.')
        .addText(text => text
            .setPlaceholder('1')
            .setValue(String(plugin.settings.gardenerRecheckDays))
            .onChange((value) => {
                void (async () => {
                    let num = parseFloat(value);
                    if (!isNaN(num) && num >= 0) {
                        // Round to 3 decimal places to avoid float jitter in data.json
                        num = Math.round(num * 1000) / 1000;
                        plugin.settings.gardenerRecheckDays = num;
                        await plugin.saveSettings();
                    }
                })();
            }));

    new Setting(containerEl)
        .setName("Skip retention (days)")
        .setDesc('How long to remember skipped files.')
        .addText(text => text
            .setPlaceholder('7')
            .setValue(String(plugin.settings.gardenerSkipRetentionDays))
            .onChange((value) => {
                void (async () => {
                    let num = parseFloat(value);
                    if (!isNaN(num) && num >= 0) {
                        // Round to 3 decimal places
                        num = Math.round(num * 1000) / 1000;
                        plugin.settings.gardenerSkipRetentionDays = num;
                        await plugin.saveSettings();
                    }
                })();
            }));

    new Setting(containerEl)
        .setName("Semantic merge threshold")
        .setDesc('Similarity score required to merge two isolated topics (from 0.5 to 1.0). Set to 1.0 to disable semantic merging.')
        .addSlider(slider => slider
            .setLimits(0.5, 1.0, 0.01)
            .setValue(plugin.settings.gardenerSemanticMergeThreshold)
            .setDynamicTooltip()
            .onChange(async (value) => {
                plugin.settings.gardenerSemanticMergeThreshold = value;
                await plugin.saveSettings();
            }));
}

function refreshSettings(plugin: IVaultIntelligencePlugin) {
    const app = plugin.app as InternalApp;
    const manifestId = (plugin as unknown as Plugin).manifest.id;
    app.setting.openTabById(manifestId);
}