import 'package:weblibre/features/bangs/data/database/drift/converters/bang_format.dart';
import 'package:weblibre/features/bangs/data/models/bang_data.dart';
import 'package:weblibre/features/bangs/data/models/bang_group.dart';
import 'package:weblibre/features/bangs/data/models/bang.dart';
import 'package:weblibre/features/bangs/data/models/search_history_entry.dart';

CREATE TABLE bang (
  "trigger" TEXT PRIMARY KEY NOT NULL,
  "group" ENUM(BangGroup) NOT NULL,
  website_name TEXT NOT NULL,
  domain TEXT NOT NULL,
  url_template TEXT NOT NULL,
  category TEXT,
  sub_category TEXT,
  format TEXT MAPPED BY `const BangFormatConverter()`
) WITH Bang;

CREATE TABLE bang_sync (
  "group" ENUM(BangGroup) PRIMARY KEY NOT NULL,
  last_sync DATETIME NOT NULL
);

CREATE TABLE bang_frequency (
  "trigger" TEXT PRIMARY KEY NOT NULL REFERENCES bang ("trigger") ON DELETE CASCADE,
  frequency INTEGER NOT NULL,
  last_used DATETIME NOT NULL
);

CREATE TABLE bang_history (
  search_query TEXT UNIQUE NOT NULL,
  "trigger" TEXT NOT NULL REFERENCES bang ("trigger"),
  search_date DATETIME NOT NULL
);

CREATE VIRTUAL TABLE bang_fts 
	USING fts5(
    trigger,
    website_name,
    content=bang,
    prefix='2 3'
  );

CREATE VIEW bang_data_view WITH BangData AS
  SELECT
    b.*,
    bf.frequency,
    bf.last_used
  FROM
    bang b
  LEFT JOIN
    bang_frequency bf ON b."trigger" = bf."trigger";

-- Triggers to keep the FTS index up to date.
CREATE TRIGGER bang_after_insert AFTER INSERT ON bang BEGIN
  INSERT INTO 
    bang_fts(rowid, "trigger", website_name) 
    VALUES (new.rowid, new."trigger", new.website_name);
END;
CREATE TRIGGER bang_after_delete AFTER DELETE ON bang BEGIN
  INSERT INTO 
    bang_fts(bang_fts, rowid, "trigger", website_name) 
    VALUES('delete', old.rowid, old."trigger", old.website_name);
END;
CREATE TRIGGER bang_after_update AFTER UPDATE ON bang BEGIN
  INSERT INTO 
    bang_fts(bang_fts, rowid, "trigger", website_name) 
    VALUES('delete', old.rowid, old."trigger", old.website_name);
  INSERT INTO 
    bang_fts(rowid, "trigger", website_name) 
    VALUES (new.rowid, new."trigger", new.website_name);
END;

optimizeFtsIndex:
  INSERT INTO bang_fts(bang_fts) VALUES ('optimize');

queryBangs WITH BangData:
  WITH weights AS (
    SELECT 
      -- Customize these weights (higher = more important)
      10.0 AS "trigger",       -- Title matches are most important
      5.0 AS website_name           -- URL matches are quite important
  )
  SELECT 
    b.*,
    bf.frequency,
    bf.last_used,
    bm25(bang_fts, weights."trigger", weights.website_name) AS weighted_rank
  FROM 
    bang_fts(:query) fts
  INNER JOIN
    bang b ON b.rowid = fts.rowid
  LEFT JOIN
    bang_frequency bf ON b."trigger" = bf."trigger"
  CROSS JOIN 
    weights
  ORDER BY 
  	weighted_rank ASC,
  	bf.frequency NULLS LAST;

queryBangsBasic WITH BangData:
  WITH weights AS (
    SELECT 
      -- Customize these weights (higher = more important)
      10.0 AS "trigger",       -- Title matches are most important
      5.0 AS website_name           -- URL matches are quite important
  )
  SELECT 
    b.*,
    bf.frequency,
    bf.last_used,
    bm25(bang_fts, weights."trigger", weights.website_name) AS weighted_rank
  FROM 
    bang_fts fts
  INNER JOIN
    bang b ON b.rowid = fts.rowid
  LEFT JOIN
    bang_frequency bf ON b."trigger" = bf."trigger"
  CROSS JOIN 
    weights
  WHERE 
  	fts."trigger" LIKE :query OR
  	fts.website_name LIKE :query
  ORDER BY 
  	weighted_rank ASC,
  	bf.frequency NULLS LAST;

categoriesJson:
  WITH categories AS (
    SELECT 
      b.category, 
      json_group_array(
        DISTINCT b.sub_category 
        ORDER BY b.sub_category
      ) AS sub_categories
    FROM 
      bang b 
    WHERE 
      b.category IS NOT NULL AND 
      b.sub_category IS NOT NULL
    GROUP BY b.category
    ORDER BY b.category
  )
  SELECT 
    json_group_object(
      c.category, 
      json(c.sub_categories)
    ) AS categories_json
  FROM categories c;

searchHistoryEntries WITH SearchHistoryEntry:
  SELECT *
  FROM bang_history 
  ORDER BY search_date DESC
  LIMIT :limit;  

evictHistoryEntries:
  DELETE FROM bang_history 
  WHERE rowid IN (
      SELECT rowid 
      FROM bang_history 
      ORDER BY search_date DESC 
      LIMIT -1 OFFSET :limit
  );