import * as dotenv from 'dotenv';
import { MongoClient, type Db, type Document } from 'mongodb';

dotenv.config();

type TextIndexFields = Record<string, 'text'>;

type CollectionIndexConfig = {
  name: string;
  fields: TextIndexFields;
};

// Add the collections you want searchable + which fields to index.
// Edit this safely any time; the script will drop/recreate the text index if needed.
const COLLECTIONS: CollectionIndexConfig[] = [
  {
    name: 'attraction',
    fields: {
      title: 'text',
      description: 'text',
      formatted_address: 'text',
      venue: 'text',
    },
  },
  {
    name: 'event',
    fields: {
      title: 'text',
      description: 'text',
      formatted_address: 'text',
      venue: 'text',
    },
  },
];

const INDEX_NAME = 'text_all';
const DEFAULT_LANG = 'english';

const mongoUri = process.env.MONGODB_URI ?? '';
if (!mongoUri) throw new Error('Missing env var: MONGODB_URI');

const sortKeys = (obj: Record<string, unknown> | undefined | null): string[] =>
  Object.keys(obj || {}).sort();

type MongoIndexInfo = {
  name: string;
  key?: Record<string, unknown>;
  weights?: Record<string, unknown>;
  default_language?: string;
};

const ensureTextIndex = async (
  db: Db,
  cfg: CollectionIndexConfig,
): Promise<void> => {
  const { name, fields } = cfg;

  const coll = db.collection<Document>(name);
  const indexes = (await coll.listIndexes().toArray()) as MongoIndexInfo[];

  // Find any existing text index (there can be only one per collection)
  const existingText = indexes.find(
    (i) => i.key && (i.key as any)._fts === 'text',
  );
  const existingNamed = indexes.find((i) => i.name === INDEX_NAME);

  // If no existing text index: create fresh
  if (!existingText) {
    console.log(`[${name}] Creating text index (${INDEX_NAME})...`);
    await coll.createIndex(fields, {
      name: INDEX_NAME,
      default_language: DEFAULT_LANG,
    });
    return;
  }

  // If a text index exists but not under our desired name, drop it and recreate
  if (existingText.name !== INDEX_NAME) {
    console.log(
      `[${name}] Found text index "${existingText.name}", expected "${INDEX_NAME}". Dropping & recreating...`,
    );
    await coll.dropIndex(existingText.name);
    await coll.createIndex(fields, {
      name: INDEX_NAME,
      default_language: DEFAULT_LANG,
    });
    return;
  }

  // Same name: check if the field set (weights) or options changed
  const existingWeights = existingNamed?.weights || {};
  const desiredKeys = sortKeys(fields);
  const existingKeys = sortKeys(existingWeights);

  const sameFieldSet =
    JSON.stringify(desiredKeys) === JSON.stringify(existingKeys);
  const sameLanguage =
    (existingNamed?.default_language || DEFAULT_LANG) === DEFAULT_LANG;

  if (sameFieldSet && sameLanguage) {
    console.log(`[${name}] Text index already up-to-date.`);
    return;
  }

  // Options changed → drop & recreate
  console.log(`[${name}] Text index changed. Dropping & recreating...`);
  await coll.dropIndex(INDEX_NAME);
  await coll.createIndex(fields, {
    name: INDEX_NAME,
    default_language: DEFAULT_LANG,
  });
};

const main = async (): Promise<void> => {
  const client = new MongoClient(mongoUri);

  try {
    await client.connect();
    const db = client.db(); // DB taken from URI path

    for (const c of COLLECTIONS) {
      await ensureTextIndex(db, c);
    }

    console.log('Indexes ensured.');
  } catch (e) {
    console.error(e);
  } finally {
    await client.close().catch(() => {});
  }
};

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
