const sqlite3 = require('sqlite3').verbose();
const path = require("path");
const fs = require("fs");

async function ensureLocalLibrarySchema(db) {
    await run(db, `
    CREATE TABLE IF NOT EXISTS local_entries (
      id TEXT PRIMARY KEY,
      type TEXT NOT NULL,
      path TEXT NOT NULL,
      folder_name TEXT NOT NULL,
      matched_id INTEGER,
      matched_source TEXT,
      last_scan INTEGER NOT NULL
    )
  `);

    await run(db, `
    CREATE TABLE IF NOT EXISTS local_files (
      id TEXT PRIMARY KEY,
      entry_id TEXT NOT NULL,
      file_path TEXT NOT NULL,
      unit_number INTEGER,
      FOREIGN KEY (entry_id) REFERENCES local_entries(id)
    )
  `);

    await run(db, `
    CREATE INDEX IF NOT EXISTS idx_local_entries_type
    ON local_entries(type)
  `);

    await run(db, `
    CREATE INDEX IF NOT EXISTS idx_local_entries_matched
    ON local_entries(matched_id)
  `);

    await run(db, `
    CREATE INDEX IF NOT EXISTS idx_local_files_entry
    ON local_files(entry_id)
  `);
}

function run(db, sql, params = []) {
    return new Promise((resolve, reject) => {
        db.run(sql, params, err => {
            if (err) reject(err);
            else resolve();
        });
    });
}

async function ensureUserDataDB(dbPath) {
    const dir = path.dirname(dbPath);

    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }

    const db = new sqlite3.Database(
        dbPath,
        sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE
    );

    return new Promise((resolve, reject) => {
        const schema = `
            CREATE TABLE IF NOT EXISTS User (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                username TEXT NOT NULL UNIQUE,
                profile_picture_url TEXT,
                email TEXT UNIQUE,
                password_hash TEXT,
                created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
            );

            CREATE TABLE IF NOT EXISTS UserIntegration (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL UNIQUE,
                platform TEXT NOT NULL DEFAULT 'AniList',
                access_token TEXT NOT NULL,
                refresh_token TEXT NOT NULL,
                token_type TEXT NOT NULL,
                anilist_user_id INTEGER NOT NULL,
                expires_at DATETIME NOT NULL,
                FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS ListEntry (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                user_id INTEGER NOT NULL,
                entry_id INTEGER NOT NULL, 
                source TEXT NOT NULL,
                entry_type TEXT NOT NULL,
                status TEXT NOT NULL,
                progress INTEGER NOT NULL DEFAULT 0,
                score INTEGER,

                start_date DATE,
                end_date DATE,
                repeat_count INTEGER NOT NULL DEFAULT 0,
                notes TEXT,
                is_private BOOLEAN NOT NULL DEFAULT 0,
                updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                UNIQUE (user_id, entry_id),
                FOREIGN KEY (user_id) REFERENCES User(id) ON DELETE CASCADE
            );
        `;

        db.exec(schema, (err) => {
            if (err) reject(err);
            else resolve(true);
        });
    });
}

async function ensureAnilistSchema(db) {
    return new Promise((resolve, reject) => {
        const schema = `
        CREATE TABLE IF NOT EXISTS anime (
            id INTEGER PRIMARY KEY,
            title TEXT,
            updatedAt INTEGER,
            cache_created_at INTEGER DEFAULT 0,
            cache_ttl_ms INTEGER DEFAULT 0,
            full_data JSON
        );

        CREATE TABLE IF NOT EXISTS trending (
            rank INTEGER PRIMARY KEY,
            id INTEGER,
            full_data JSON,
            updated_at INTEGER NOT NULL DEFAULT 0
        );

        CREATE TABLE IF NOT EXISTS top_airing (
            rank INTEGER PRIMARY KEY,
            id INTEGER,
            full_data JSON,
            updated_at INTEGER NOT NULL DEFAULT 0
        );

        CREATE TABLE IF NOT EXISTS books (
            id INTEGER PRIMARY KEY,
            title TEXT,
            updatedAt INTEGER,
            full_data JSON
        );

        CREATE TABLE IF NOT EXISTS trending_books (
            rank INTEGER PRIMARY KEY,
            id INTEGER,
            full_data JSON,
            updated_at INTEGER NOT NULL DEFAULT 0
        );

        CREATE TABLE IF NOT EXISTS popular_books (
            rank INTEGER PRIMARY KEY,
            id INTEGER,
            full_data JSON,
            updated_at INTEGER NOT NULL DEFAULT 0
        );
        `;

        db.exec(schema, (err) => {
            if (err) reject(err);
            else resolve(true);
        });
    });
}

async function ensureExtensionsTable(db) {
    return new Promise((resolve, reject) => {
        db.exec(`
            CREATE TABLE IF NOT EXISTS extension (
                ext_name TEXT NOT NULL,
                id TEXT NOT NULL,
                title TEXT NOT NULL,
                metadata TEXT NOT NULL,
                updated_at INTEGER NOT NULL,
                PRIMARY KEY(ext_name, id)
            );
        `, (err) => {
            if (err) reject(err);
            else resolve(true);
        });
    });
}

async function ensureCacheTable(db) {
    return new Promise((resolve, reject) => {
        db.exec(`
            CREATE TABLE IF NOT EXISTS cache (
                key TEXT PRIMARY KEY,
                result TEXT NOT NULL,
                created_at INTEGER NOT NULL,
                ttl_ms INTEGER NOT NULL
            );
        `, (err) => {
            if (err) reject(err);
            else resolve(true);
        });
    });
}

function ensureFavoritesDB(dbPath) {
    const dir = path.dirname(dbPath);

    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }

    const exists = fs.existsSync(dbPath);

    const db = new sqlite3.Database(
        dbPath,
        sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE
    );

    return new Promise((resolve, reject) => {
        if (!exists) {
            const schema = `
                CREATE TABLE IF NOT EXISTS favorites (
                    id TEXT NOT NULL,
                    user_id INTEGER NOT NULL,
                    title TEXT NOT NULL,
                    image_url TEXT NOT NULL,
                    thumbnail_url TEXT NOT NULL DEFAULT "",
                    tags TEXT NOT NULL DEFAULT "",
                    headers TEXT NOT NULL DEFAULT "",
                    provider TEXT NOT NULL DEFAULT "",
                    PRIMARY KEY (id, user_id)
                );
            `;

            db.exec(schema, (err) => {
                if (err) reject(err);
                else resolve(true);
            });

            return;
        }

        db.all(`PRAGMA table_info(favorites)`, (err, cols) => {
            if (err) return reject(err);

            const hasHeaders  = cols.some(c => c.name === "headers");
            const hasProvider = cols.some(c => c.name === "provider");
            const hasUserId   = cols.some(c => c.name === "user_id");

            const queries = [];

            if (!hasHeaders) {
                queries.push(`ALTER TABLE favorites ADD COLUMN headers TEXT NOT NULL DEFAULT ""`);
            }

            if (!hasProvider) {
                queries.push(`ALTER TABLE favorites ADD COLUMN provider TEXT NOT NULL DEFAULT ""`);
            }

            if (!hasUserId) {
                queries.push(`ALTER TABLE favorites ADD COLUMN user_id INTEGER NOT NULL DEFAULT 1`);
            }

            if (queries.length === 0) {
                return resolve(false);
            }

            db.exec(queries.join(";"), (err) => {
                if (err) reject(err);
                else resolve(true);
            });
        });
    });
}

module.exports = {
    ensureUserDataDB,
    ensureAnilistSchema,
    ensureExtensionsTable,
    ensureCacheTable,
    ensureFavoritesDB,
    ensureLocalLibrarySchema
};