// Database Layer for Feed Storage

import * as SQLite from 'expo-sqlite';
import { FeedSubscription, FeedItem } from '@/types/feed';

let db: SQLite.SQLiteDatabase | null = null;

export async function initDatabase(): Promise<void> {
  if (db) return;

  try {
    db = await SQLite.openDatabaseAsync('rssuper.db');

    await db.execAsync(`
      CREATE TABLE IF NOT EXISTS subscriptions (
        id TEXT PRIMARY KEY,
        url TEXT NOT NULL UNIQUE,
        title TEXT,
        category TEXT,
        enabled INTEGER DEFAULT 1,
        fetch_interval INTEGER DEFAULT 60,
        http_auth_username TEXT,
        http_auth_password TEXT,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        last_fetched_at DATETIME,
        next_fetch_at DATETIME,
        error TEXT
      );

      CREATE TABLE IF NOT EXISTS feeds (
        id TEXT PRIMARY KEY,
        subscription_id TEXT NOT NULL,
        title TEXT,
        link TEXT,
        description TEXT,
        author TEXT,
        published DATETIME,
        updated DATETIME,
        content TEXT,
        guid TEXT UNIQUE,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (subscription_id) REFERENCES subscriptions(id)
      );

      CREATE INDEX IF NOT EXISTS idx_feeds_subscription ON feeds(subscription_id);
      CREATE INDEX IF NOT EXISTS idx_feeds_published ON feeds(published DESC);
      CREATE INDEX IF NOT EXISTS idx_subscriptions_next_fetch ON subscriptions(next_fetch_at);
      CREATE INDEX IF NOT EXISTS idx_feeds_author ON feeds(author);
      CREATE INDEX IF NOT EXISTS idx_feeds_link ON feeds(link);

      CREATE VIRTUAL TABLE IF NOT EXISTS feeds_fts USING fts5(
        title,
        description,
        content,
        content='feeds',
        content_rowid='rowid'
      );

      CREATE VIRTUAL TABLE IF NOT EXISTS subscriptions_fts USING fts5(
        title,
        url,
        content='subscriptions',
        content_rowid='rowid'
      );

      CREATE TRIGGER IF NOT EXISTS feeds_ai AFTER INSERT ON feeds BEGIN
        INSERT INTO feeds_fts(rowid, title, description, content)
        VALUES (new.rowid, new.title, new.description, new.content);
      END;

      CREATE TRIGGER IF NOT EXISTS feeds_ad AFTER DELETE ON feeds BEGIN
        INSERT INTO feeds_fts(feeds_fts, rowid, title, description, content)
        VALUES ('delete', old.rowid, old.title, old.description, old.content);
      END;

      CREATE TRIGGER IF NOT EXISTS feeds_au AFTER UPDATE ON feeds BEGIN
        INSERT INTO feeds_fts(feeds_fts, rowid, title, description, content)
        VALUES ('delete', old.rowid, old.title, old.description, old.content);
        INSERT INTO feeds_fts(rowid, title, description, content)
        VALUES (new.rowid, new.title, new.description, new.content);
      END;

      CREATE TRIGGER IF NOT EXISTS subscriptions_ai AFTER INSERT ON subscriptions BEGIN
        INSERT INTO subscriptions_fts(rowid, title, url)
        VALUES (new.rowid, new.title, new.url);
      END;

      CREATE TRIGGER IF NOT EXISTS subscriptions_ad AFTER DELETE ON subscriptions BEGIN
        INSERT INTO subscriptions_fts(subscriptions_fts, rowid, title, url)
        VALUES ('delete', old.rowid, old.title, old.url);
      END;

      CREATE TRIGGER IF NOT EXISTS subscriptions_au AFTER UPDATE ON subscriptions BEGIN
        INSERT INTO subscriptions_fts(subscriptions_fts, rowid, title, url)
        VALUES ('delete', old.rowid, old.title, old.url);
        INSERT INTO subscriptions_fts(rowid, title, url)
        VALUES (new.rowid, new.title, new.url);
      END;

      CREATE TABLE IF NOT EXISTS search_history (
        id TEXT PRIMARY KEY,
        query TEXT NOT NULL,
        timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
      );

      CREATE INDEX IF NOT EXISTS idx_search_history_timestamp ON search_history(timestamp DESC);
    `);

    console.log('Database initialized successfully');
  } catch (error) {
    console.error('Failed to initialize database:', error);
    throw error;
  }
}

// Helper to get database instance
export async function getDb(): Promise<SQLite.SQLiteDatabase> {
  if (!db) await initDatabase();
  if (!db) throw new Error('Database not initialized');
  return db;
}

// Subscription CRUD

export async function saveSubscription(sub: FeedSubscription): Promise<void> {
  const database = await getDb();

  await database.runAsync(
    `INSERT OR REPLACE INTO subscriptions 
      (id, url, title, category, enabled, fetch_interval, 
       http_auth_username, http_auth_password, updated_at, 
       last_fetched_at, next_fetch_at, error)
     VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, ?, ?, ?)`,
    [
      sub.id,
      sub.url,
      sub.title,
      sub.category || null,
      sub.enabled ? 1 : 0,
      sub.fetchInterval,
      sub.httpAuth?.username || null,
      sub.httpAuth?.password || null,
      sub.lastFetchedAt?.toISOString() || null,
      sub.nextFetchAt?.toISOString() || null,
      sub.error || null,
    ]
  );
}

export async function getSubscription(id: string): Promise<FeedSubscription | null> {
  const database = await getDb();

  const row = await database.getFirstAsync<any>(
    'SELECT * FROM subscriptions WHERE id = ?',
    [id]
  );

  if (!row) return null;

  return rowToSubscription(row);
}

export async function getAllSubscriptions(): Promise<FeedSubscription[]> {
  const database = await getDb();

  const rows = await database.getAllAsync<any>('SELECT * FROM subscriptions ORDER BY title');
  return rows.map(rowToSubscription);
}

export async function deleteSubscription(id: string): Promise<void> {
  const database = await getDb();

  await database.runAsync('DELETE FROM subscriptions WHERE id = ?', [id]);
  await database.runAsync('DELETE FROM feeds WHERE subscription_id = ?', [id]);
}

// Feed Item CRUD

export async function saveFeedItems(
  subscriptionId: string,
  items: FeedItem[]
): Promise<void> {
  const database = await getDb();

  const insertQuery = `
    INSERT OR REPLACE INTO feeds 
      (id, subscription_id, title, link, description, author, 
       published, updated, content, guid)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `;

  for (const item of items) {
    await database.runAsync(insertQuery, [
      item.id,
      subscriptionId,
      item.title || null,
      item.link || null,
      item.description || null,
      item.author || null,
      item.published?.toISOString() || null,
      item.updated?.toISOString() || null,
      item.content || null,
      item.guid || null,
    ]);
  }
}

export async function getFeedItems(
  subscriptionId?: string,
  limit: number = 50,
  offset: number = 0
): Promise<FeedItem[]> {
  const database = await getDb();

  let query = 'SELECT f.*, s.title as subscription_title FROM feeds f '
    + 'LEFT JOIN subscriptions s ON f.subscription_id = s.id ';
  
  const params: any[] = [];
  
  if (subscriptionId) {
    query += 'WHERE f.subscription_id = ? ';
    params.push(subscriptionId);
  }
  
  query += 'ORDER BY f.published DESC LIMIT ? OFFSET ?';
  params.push(limit, offset);

  const rows = await database.getAllAsync<any>(query, params);
  return rows.map(rowToFeedItem);
}

export async function getAllFeedItems(limit: number = 100, offset: number = 0): Promise<FeedItem[]> {
  const database = await getDb();

  const rows = await database.getAllAsync<any>(
    'SELECT f.*, s.title as subscription_title FROM feeds f '
    + 'LEFT JOIN subscriptions s ON f.subscription_id = s.id '
    + 'ORDER BY f.published DESC LIMIT ? OFFSET ?',
    [limit, offset]
  );
  return rows.map(rowToFeedItem);
}

// Helper functions

function rowToSubscription(row: any): FeedSubscription {
  return {
    id: row.id,
    url: row.url,
    title: row.title || 'Untitled',
    category: row.category,
    enabled: row.enabled === 1,
    fetchInterval: row.fetch_interval,
    httpAuth: row.http_auth_username && row.http_auth_password ? {
      username: row.http_auth_username,
      password: row.http_auth_password,
    } : undefined,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
    lastFetchedAt: row.last_fetched_at ? new Date(row.last_fetched_at) : undefined,
    nextFetchAt: row.next_fetch_at ? new Date(row.next_fetch_at) : undefined,
    error: row.error,
  };
}

function rowToFeedItem(row: any): FeedItem {
  return {
    id: row.id,
    title: row.title || '',
    link: row.link,
    description: row.description,
    content: row.content,
    author: row.author,
    published: row.published ? new Date(row.published) : undefined,
    updated: row.updated ? new Date(row.updated) : undefined,
    guid: row.guid,
    subscriptionTitle: row.subscription_title,
  };
}

export async function closeDatabase(): Promise<void> {
  if (db) {
    await db.closeAsync();
    db = null;
  }
}

// Search History Functions

export async function addToSearchHistory(query: string): Promise<void> {
  const database = await getDb();
  const id = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  
  await database.runAsync(
    'INSERT OR REPLACE INTO search_history (id, query, timestamp) VALUES (?, ?, CURRENT_TIMESTAMP)',
    [id, query]
  );
}

export async function getSearchHistory(limit: number = 10): Promise<{ query: string; timestamp: string }[]> {
  const database = await getDb();
  
  const rows = await database.getAllAsync<any>(
    'SELECT query, timestamp FROM search_history ORDER BY timestamp DESC LIMIT ?',
    [limit]
  );
  
  return rows.map(row => ({ query: row.query, timestamp: row.timestamp }));
}

export async function clearSearchHistory(): Promise<void> {
  const database = await getDb();
  await database.runAsync('DELETE FROM search_history');
}

export async function removeSearchHistoryItem(query: string): Promise<void> {
  const database = await getDb();
  await database.runAsync('DELETE FROM search_history WHERE query = ?', [query]);
}
