/**
 * Environment File Manager
 *
 * Handles reading and writing .env configuration files.
 * Provides type-safe access to environment variables.
 */

import * as fs from 'fs';
import * as path from 'path';

export interface EnvConfig {
    LLM_BACKEND?: string;
    OLLAMA_HOST?: string;
    OLLAMA_MODEL?: string;
    OLLAMA_EMBEDDING_MODEL?: string;
    OPENAI_API_KEY?: string;
    OPENAI_MODEL?: string;
    OPENAI_EMBEDDING_MODEL?: string;
    DATA_DIR?: string;
    LIGHTRAG_DIR?: string;
    ETL_PROFILE?: string;
    [key: string]: string | undefined;
}

const DEFAULT_ENV: EnvConfig = {
    LLM_BACKEND: 'ollama',
    OLLAMA_HOST: 'http://localhost:11434',
    OLLAMA_MODEL: 'qwen2.5:7b',
    OLLAMA_EMBEDDING_MODEL: 'nomic-embed-text',
    OPENAI_API_KEY: '',
    OPENAI_MODEL: 'gpt-4o-mini',
    OPENAI_EMBEDDING_MODEL: 'text-embedding-3-small',
    DATA_DIR: './data',
    LIGHTRAG_DIR: './data/lightrag',
    ETL_PROFILE: 'default'
};

export class EnvManager {
    private workspaceRoot: string;
    private projectRoot: string;
    private envPath: string;

    constructor(workspaceRoot: string) {
        this.workspaceRoot = workspaceRoot;
        this.projectRoot = this.findProjectRoot(workspaceRoot);
        this.envPath = path.join(this.projectRoot, '.env');
    }

    /**
     * Find the project root by looking for pyproject.toml or src/server.py
     */
    private findProjectRoot(startPath: string): string {
        let current = startPath;
        const root = path.parse(current).root;

        while (current !== root) {
            if (fs.existsSync(path.join(current, 'pyproject.toml')) ||
                fs.existsSync(path.join(current, 'src', 'server.py'))) {
                return current;
            }
            current = path.dirname(current);
        }

        return startPath;
    }

    /**
     * Get the path to the .env file
     */
    getEnvPath(): string {
        return this.envPath;
    }

    /**
     * Get the manifest path for a document, supporting both legacy and current layouts.
     */
    getManifestPath(docId: string): string | null {
        return this.findManifestPath(path.join(this.getDataDir(), docId), docId);
    }

    /**
     * Check if .env file exists
     */
    exists(): boolean {
        return fs.existsSync(this.envPath);
    }

    /**
     * Read and parse .env file
     */
    async readEnv(): Promise<EnvConfig> {
        if (!this.exists()) {
            return { ...DEFAULT_ENV };
        }

        try {
            const content = fs.readFileSync(this.envPath, 'utf-8');
            return this.parseEnvContent(content);
        } catch (error) {
            console.error('Error reading .env file:', error);
            return { ...DEFAULT_ENV };
        }
    }

    /**
     * Parse .env content to object
     */
    private parseEnvContent(content: string): EnvConfig {
        const env: EnvConfig = { ...DEFAULT_ENV };
        const lines = content.split('\n');

        for (const line of lines) {
            const trimmed = line.trim();

            // Skip empty lines and comments
            if (!trimmed || trimmed.startsWith('#')) {
                continue;
            }

            const eqIndex = trimmed.indexOf('=');
            if (eqIndex > 0) {
                const key = trimmed.substring(0, eqIndex).trim();
                let value = trimmed.substring(eqIndex + 1).trim();

                // Remove quotes if present
                if ((value.startsWith('"') && value.endsWith('"')) ||
                    (value.startsWith("'") && value.endsWith("'"))) {
                    value = value.slice(1, -1);
                }

                env[key] = value;
            }
        }

        return env;
    }

    /**
     * Create default .env file
     */
    async createDefaultEnv(): Promise<void> {
        const content = this.generateEnvContent(DEFAULT_ENV);
        fs.mkdirSync(path.dirname(this.envPath), { recursive: true });
        fs.writeFileSync(this.envPath, content, 'utf-8');
    }

    /**
     * Update a single environment variable
     */
    async updateEnv(key: string, value: string): Promise<void> {
        const env = await this.readEnv();
        env[key] = value;
        await this.writeEnv(env);
    }

    /**
     * Write entire env config to file
     */
    async writeEnv(env: EnvConfig): Promise<void> {
        const content = this.generateEnvContent(env);
        fs.mkdirSync(path.dirname(this.envPath), { recursive: true });
        fs.writeFileSync(this.envPath, content, 'utf-8');
    }

    private findManifestPath(docPath: string, docId: string): string | null {
        const candidates = [
            path.join(docPath, `${docId}_manifest.json`),
            path.join(docPath, 'manifest.json'),
        ];

        for (const candidate of candidates) {
            if (fs.existsSync(candidate)) {
                return candidate;
            }
        }

        return null;
    }

    /**
     * Generate .env file content from config
     */
    private generateEnvContent(env: EnvConfig): string {
        const lines: string[] = [
            '# Asset-Aware MCP Configuration',
            '# Generated by VS Code Extension',
            '',
            '# ============================================',
            '# LLM Backend Selection',
            '# ============================================',
            '# Options: "ollama" (local) or "openai" (cloud)',
            `LLM_BACKEND=${env.LLM_BACKEND || 'ollama'}`,
            '',
            '# ============================================',
            '# ETL Profile (Document Extraction Settings)',
            '# ============================================',
            '# Options: "default", "arxiv", "nature", "ieee", "elsevier"',
            `ETL_PROFILE=${env.ETL_PROFILE || 'default'}`,
            '',
            '# ============================================',
            '# Ollama Settings (for local LLM)',
            '# ============================================',
            `OLLAMA_HOST=${env.OLLAMA_HOST || 'http://localhost:11434'}`,
            `OLLAMA_MODEL=${env.OLLAMA_MODEL || 'qwen2.5:7b'}`,
            `OLLAMA_EMBEDDING_MODEL=${env.OLLAMA_EMBEDDING_MODEL || 'nomic-embed-text'}`,
            '',
            '# ============================================',
            '# OpenAI Settings (for cloud LLM)',
            '# ============================================',
            `OPENAI_API_KEY=${env.OPENAI_API_KEY || ''}`,
            `OPENAI_MODEL=${env.OPENAI_MODEL || 'gpt-4o-mini'}`,
            `OPENAI_EMBEDDING_MODEL=${env.OPENAI_EMBEDDING_MODEL || 'text-embedding-3-small'}`,
            '',
            '# ============================================',
            '# Storage Settings',
            '# ============================================',
            `DATA_DIR=${env.DATA_DIR || './data'}`,
            `LIGHTRAG_DIR=${env.LIGHTRAG_DIR || './data/lightrag'}`,
            ''
        ];

        return lines.join('\n');
    }

    /**
     * Get data directory path
     */
    getDataDir(): string {
        const env = this.readEnvSync();
        const dataDir = env.DATA_DIR || './data';
        if (path.isAbsolute(dataDir)) {
            return dataDir;
        }
        return path.resolve(this.projectRoot, dataDir);
    }

    /**
     * Synchronous read for quick access
     */
    private readEnvSync(): EnvConfig {
        if (!this.exists()) {
            return { ...DEFAULT_ENV };
        }

        try {
            const content = fs.readFileSync(this.envPath, 'utf-8');
            return this.parseEnvContent(content);
        } catch {
            return { ...DEFAULT_ENV };
        }
    }

    /**
     * List ingested documents from data directory
     */
    listDocuments(): { id: string; path: string; manifestExists: boolean }[] {
        const dataDir = this.getDataDir();
        const documents: { id: string; path: string; manifestExists: boolean }[] = [];

        if (!fs.existsSync(dataDir)) {
            return documents;
        }

        try {
            const entries = fs.readdirSync(dataDir, { withFileTypes: true });

            for (const entry of entries) {
                if (entry.isDirectory() && entry.name.startsWith('doc_')) {
                    const docPath = path.join(dataDir, entry.name);
                    const manifestPath = this.findManifestPath(docPath, entry.name);

                    documents.push({
                        id: entry.name,
                        path: docPath,
                        manifestExists: manifestPath !== null
                    });
                }
            }
        } catch (error) {
            console.error('Error listing documents:', error);
        }

        return documents;
    }

    /**
     * List A2T tables from tables directory
     */
    listTables(): { id: string; title: string; path: string; mdPath: string }[] {
        const dataDir = this.getDataDir();
        const tablesDir = path.join(dataDir, 'tables');
        const tables: { id: string; title: string; path: string; mdPath: string }[] = [];

        if (!fs.existsSync(tablesDir)) {
            return tables;
        }

        try {
            const entries = fs.readdirSync(tablesDir, { withFileTypes: true });
            for (const entry of entries) {
                if (entry.isFile() && entry.name.endsWith('.json') && entry.name.startsWith('tbl_')) {
                    const tableId = entry.name.replace('.json', '');
                    const jsonPath = path.join(tablesDir, entry.name);
                    const mdPath = path.join(tablesDir, `${tableId}.md`);

                    try {
                        const content = fs.readFileSync(jsonPath, 'utf-8');
                        const data = JSON.parse(content);
                        tables.push({
                            id: tableId,
                            title: data.title || tableId,
                            path: jsonPath,
                            mdPath: fs.existsSync(mdPath) ? mdPath : ''
                        });
                    } catch {
                        // Skip invalid JSON
                    }
                }
            }
        } catch (error) {
            console.error('Error listing tables:', error);
        }

        return tables;
    }

    /**
     * List A2T drafts from drafts directory
     */
    listDrafts(): { id: string; title: string; path: string }[] {
        const dataDir = this.getDataDir();
        const draftsDir = path.join(dataDir, 'tables', 'drafts');
        const drafts: { id: string; title: string; path: string }[] = [];

        if (!fs.existsSync(draftsDir)) {
            return drafts;
        }

        try {
            const entries = fs.readdirSync(draftsDir, { withFileTypes: true });
            for (const entry of entries) {
                if (entry.isFile() && entry.name.endsWith('.json') && entry.name.startsWith('draft_')) {
                    const draftId = entry.name.replace('.json', '');
                    const jsonPath = path.join(draftsDir, entry.name);

                    try {
                        const content = fs.readFileSync(jsonPath, 'utf-8');
                        const data = JSON.parse(content);
                        drafts.push({
                            id: draftId,
                            title: data.title || draftId,
                            path: jsonPath
                        });
                    } catch {
                        // Skip invalid JSON
                    }
                }
            }
        } catch (error) {
            console.error('Error listing drafts:', error);
        }

        return drafts;
    }

    /**
     * Read document manifest
     */
    readManifest(docId: string): object | null {
        const manifestPath = this.getManifestPath(docId);

        if (!manifestPath) {
            return null;
        }

        try {
            const content = fs.readFileSync(manifestPath, 'utf-8');
            return JSON.parse(content);
        } catch {
            return null;
        }
    }
}
