import fs from 'node:fs';
import { chain } from 'stream-chain';
import { parser } from 'stream-json';
import { streamObject } from 'stream-json/streamers/StreamObject';
import { create, insert, search } from '@orama/orama';
import { normalize } from '@star-kitten/util/text.js';
import { getType, type Type } from '@/models/type';

const db = create({
  schema: {
    type_id: 'number',
    name: {
      en: 'string',
      de: 'string',
      fr: 'string',
      ru: 'string',
      ja: 'string',
      zh: 'string',
    },
  },
});

export async function initializeTypeSearch() {
  return new Promise((resolve, reject) => {
    const pipeline = chain([fs.createReadStream('../../data/reference-data/types.json'), parser(), streamObject(), (data) => data]);

    pipeline.on('data', async ({ value }) => {
      if (value && value.market_group_id && value.published) {
        try {
          await addType(value);
        } catch (e) {
          reject(e);
        }
      }
    });
    pipeline.on('error', reject);
    pipeline.on('end', resolve);
  });
}

const addType = async (type: Type) =>
  await insert(db, {
    type_id: type.type_id,
    name: type.name,
  });

export async function typeSearch(name: string) {
  let now = Date.now();
  const normalizedName = normalize(name);
  if (normalizedName.length > 100) return null;
  const results = await search(db, {
    term: normalizedName,
    limit: 1,
    tolerance: 0,
  });
  if (!results || results.count === 0) return null;
  now = Date.now();
  const type = await getType(results.hits[0].document.type_id);
  return type;
}

export async function typeSearchAutoComplete(name: string) {
  const normalizedName = normalize(name);
  if (normalizedName.length > 100) return null;
  const results = await search(db, {
    term: normalizedName,
  });
  if (!results || results.count === 0) return null;
  return results.hits.map((hit) => ({
    name: hit.document.name.en,
    value: hit.document.name.en,
  }));
}
