import { Database } from "sql.js";

import { CardData, CardMeta, CardText } from "@/api";
const TYPE_MONSTER = 0x1;

export interface FtsConditions {
  // 过滤条件
  types?: number[]; // 卡片类型
  levels?: number[]; // 星阶/刻度/link值
  atk?: [number, number]; // 攻击力区间
  def?: [number, number]; // 防御力区间
  races?: number[]; // 种族
  attributes?: number[]; // 属性
}
export interface FtsParams {
  query: string; // 用于全文检索的query
  conditions: FtsConditions; // 过滤条件
}

export function invokeFts(db: Database, params: FtsParams): CardMeta[] {
  const { query, conditions } = params;
  const ftsTexts: CardText[] = [];
  const ftsMetas: CardMeta[] = [];

  const textStmt = db.prepare("SELECT * FROM texts WHERE name LIKE $query");
  textStmt.bind({ $query: `%${query}%` });

  while (textStmt.step()) {
    const row = textStmt.getAsObject();
    ftsTexts.push(row);
  }

  for (const text of ftsTexts) {
    const id = text.id;
    if (id) {
      const filterConditions = getFtsCondtions(conditions);
      const sql = `SELECT * FROM datas WHERE ${
        filterConditions == "" ? "ID = $id" : `ID = $id AND ${filterConditions}`
      }`;
      const dataStmt = db.prepare(sql);
      const data: CardData = dataStmt.getAsObject({ $id: id });
      if (Object.values(data).filter((v) => v !== undefined).length > 0) {
        ftsMetas.push({ id, data, text });
      }
    }
  }

  return ftsMetas;
}

function getFtsCondtions(conditions: FtsConditions): string {
  const { types, levels, atk, def, races, attributes } = conditions;
  const assertMonster = `(type & ${TYPE_MONSTER}) > 0`;

  const typesCondition = types
    ?.map((type) => `(type & ${type}) > 0`)
    .join(" OR ");
  const levelsCondition = levels
    ?.map((level) => `level = ${level}`)
    .join(" OR ");
  const atkCondition = atk
    ? `atk BETWEEN ${atk[0]} AND ${atk[1]} AND ${assertMonster}`
    : undefined;
  const defCondition = def
    ? `def BETWEEN ${def[0]} AND ${def[1]} AND ${assertMonster}`
    : undefined;
  const raceCondition = races?.map((race) => `race = ${race}`).join(" OR ");
  const attributeCondition = attributes
    ?.map((attribute) => `attribute = ${attribute}`)
    .join(" OR ");

  const merged = [
    typesCondition,
    levelsCondition,
    atkCondition,
    defCondition,
    raceCondition,
    attributeCondition,
  ]
    .filter((condition) => condition !== undefined && condition !== "")
    .map((condition) => `(${condition})`)
    .join(" AND ");

  return merged;
}
