import { Injectable } from '@nestjs/common';
import Database from 'better-sqlite3';
import fs from 'fs';
import path from 'path';

@Injectable()
export class ConfigService {
  private dataDir: string;
  private unifiedDbPath: string;

  constructor() {
    // Find project root by traversing up from current directory until we find the root package.json
    let projectRoot = process.cwd();
    while (projectRoot !== path.dirname(projectRoot)) {
      if (fs.existsSync(path.join(projectRoot, 'package.json'))) {
        try {
          const pkg = JSON.parse(
            fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf-8'),
          );
          if (pkg.name === 'watch-finished-turbo') {
            break;
          }
        } catch (e) {
          // ignore
        }
      }
      projectRoot = path.dirname(projectRoot);
    }

    this.dataDir = path.resolve(projectRoot, 'data');
    this.unifiedDbPath = path.resolve(this.dataDir, 'database.db');

    console.log('ConfigService: Database path:', this.unifiedDbPath);
    console.log('ConfigService: Project root:', projectRoot);
    console.log('ConfigService: Current working directory:', process.cwd());

    // Ensure database and tables exist
    const db = new Database(this.unifiedDbPath);
    db.exec(`
      CREATE TABLE IF NOT EXISTS settings (
        key TEXT PRIMARY KEY,
        value TEXT
      );
    `);
    db.close();
  }

  getSettings(key?: string, defaultValue?: any): any {
    try {
      const db = new Database(this.unifiedDbPath, { readonly: true });
      if (key) {
        const row = db
          .prepare('SELECT value FROM settings WHERE key = ?')
          .get(key) as { value?: string } | undefined;
        db.close();
        return row && row.value !== undefined
          ? JSON.parse(row.value)
          : defaultValue;
      } else {
        const rows = db
          .prepare('SELECT key, value FROM settings')
          .all() as Array<{ key: string; value: string }>;
        db.close();
        const settings: Record<string, any> = {};
        for (const row of rows) {
          settings[row.key] = JSON.parse(row.value);
        }
        return settings;
      }
    } catch (e) {
      if (key) return defaultValue;
      return {};
    }
  }

  getConfigFile(name: string): any {
    // For datasources: name = kids.json, pr0n.json, tvshows.json
    const base = name.replace(/\.json$/, '');
    try {
      const db = new Database(this.unifiedDbPath, { readonly: true });
      const row = db
        .prepare('SELECT data FROM datasets WHERE name = ?')
        .get(base) as { data?: string } | undefined;
      db.close();
      return row && row.data !== undefined ? JSON.parse(row.data) : null;
    } catch (e) {
      return null;
    }
  }

  listConfigs(): string[] {
    // Return all dataset names as .json (regardless of enabled)
    try {
      const db = new Database(this.unifiedDbPath, { readonly: true });
      const rows = db.prepare('SELECT name FROM datasets').all() as Array<{
        name: string;
      }>;
      db.close();
      // Debug: log found rows
      if (rows.length === 0) {
        console.warn('No configs found in datasets table');
      }
      return rows.map((row) => row.name + '.json');
    } catch (e) {
      console.error('Error in listConfigs:', e);
      return [];
    }
  }

  setSettings(settings: Record<string, any>): boolean {
    try {
      const db = new Database(this.unifiedDbPath);
      const insert = db.prepare(
        'INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)',
      );
      for (const [key, value] of Object.entries(settings)) {
        // If value is already a JSON string, save it as-is
        // Otherwise, stringify it
        let valueToSave: string;
        if (typeof value === 'string') {
          // Check if it's already valid JSON
          try {
            JSON.parse(value);
            valueToSave = value;
          } catch {
            // Not valid JSON, stringify it
            valueToSave = JSON.stringify(value);
          }
        } else {
          // It's an object, stringify it
          valueToSave = JSON.stringify(value);
        }
        insert.run(key, valueToSave);
      }
      db.close();
      return true;
    } catch (e) {
      console.error('Error setting settings:', e);
      return false;
    }
  }

  deleteSetting(key: string): boolean {
    try {
      const db = new Database(this.unifiedDbPath);
      const result = db.prepare('DELETE FROM settings WHERE key = ?').run(key);
      db.close();
      return result.changes > 0;
    } catch (e) {
      console.error('Error deleting setting:', e);
      return false;
    }
  }
}
