import { createRequire } from 'module';
import PocketBase from 'pocketbase';

const require = createRequire(import.meta.url);

let runtimeConfig = {};
try {
  runtimeConfig = require('../pocket-base/bai_api_pb_hooks/bai_api_shared/config/runtime.js');
} catch (_error) {
  runtimeConfig = {};
}

const PB_URL = String(process.env.PB_URL || 'https://bai-api.blv-oa.com/pb').replace(/\/+$/, '');
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
const COLLECTION = 'tbl_cart';
const ACTIVE_UNIQUE_INDEX = 'CREATE UNIQUE INDEX idx_tbl_cart_owner_product_active_unique ON tbl_cart (cart_owner, cart_product_id) WHERE is_delete = 0';
const TEMP_RULE = '@request.auth.id != ""';

if (!AUTH_TOKEN) {
  console.error('Missing POCKETBASE_AUTH_TOKEN');
  process.exit(1);
}

const pb = new PocketBase(PB_URL);

function buildCollectionPayload(base, overrides = {}) {
  const rawFields = Array.isArray(base.fields) ? base.fields : [];
  const safeFields = rawFields.filter((field) => field && field.name !== 'id');

  return {
    name: base.name,
    type: base.type,
    listRule: Object.prototype.hasOwnProperty.call(overrides, 'listRule') ? overrides.listRule : base.listRule,
    viewRule: Object.prototype.hasOwnProperty.call(overrides, 'viewRule') ? overrides.viewRule : base.viewRule,
    createRule: Object.prototype.hasOwnProperty.call(overrides, 'createRule') ? overrides.createRule : base.createRule,
    updateRule: Object.prototype.hasOwnProperty.call(overrides, 'updateRule') ? overrides.updateRule : base.updateRule,
    deleteRule: Object.prototype.hasOwnProperty.call(overrides, 'deleteRule') ? overrides.deleteRule : base.deleteRule,
    fields: safeFields,
    indexes: Object.prototype.hasOwnProperty.call(overrides, 'indexes') ? overrides.indexes : (base.indexes || []),
  };
}

async function setTempRules(collection) {
  const payload = buildCollectionPayload(collection, {
    listRule: TEMP_RULE,
    viewRule: TEMP_RULE,
    createRule: TEMP_RULE,
    updateRule: TEMP_RULE,
    deleteRule: TEMP_RULE,
  });
  await pb.collections.update(collection.id, payload);
}

async function restoreRules(collection) {
  await pb.collections.update(collection.id, buildCollectionPayload(collection));
}

function groupKey(record) {
  const owner = String(record.cart_owner || '').trim();
  const product = String(record.cart_product_id || '').trim();
  return `${owner}||${product}`;
}

async function dedupeActiveRows() {
  const rows = await pb.collection(COLLECTION).getFullList({
    filter: 'is_delete = 0',
    sort: '-updated',
    fields: 'id,cart_owner,cart_product_id,is_delete,updated',
  });

  const groups = new Map();
  for (const row of rows) {
    const key = groupKey(row);
    if (!groups.has(key)) groups.set(key, []);
    groups.get(key).push(row);
  }

  let duplicateGroups = 0;
  let softDeleted = 0;

  for (const [, items] of groups) {
    if (items.length <= 1) continue;
    duplicateGroups += 1;

    const keep = items[0];
    for (let i = 1; i < items.length; i += 1) {
      const row = items[i];
      await pb.collection(COLLECTION).update(row.id, { is_delete: 1 });
      softDeleted += 1;
    }

    console.log(`dedupe group keep=${keep.id} deleted=${items.length - 1}`);
  }

  return { total: rows.length, duplicateGroups, softDeleted };
}

async function applyActiveUniqueIndex() {
  const collection = await pb.collections.getOne(COLLECTION);
  const indexes = Array.isArray(collection.indexes) ? collection.indexes.slice() : [];
  if (!indexes.includes(ACTIVE_UNIQUE_INDEX)) {
    indexes.push(ACTIVE_UNIQUE_INDEX);
  }

  const payload = buildCollectionPayload(collection, { indexes });
  await pb.collections.update(collection.id, payload);

  const latest = await pb.collections.getOne(COLLECTION);
  const ok = Array.isArray(latest.indexes) && latest.indexes.includes(ACTIVE_UNIQUE_INDEX);
  if (!ok) {
    throw new Error('Active unique index was not applied.');
  }
}

async function main() {
  pb.authStore.save(AUTH_TOKEN, null);
  console.log(`connect ${PB_URL}`);

  const original = await pb.collections.getOne(COLLECTION);

  try {
    await setTempRules(original);
    const dedupe = await dedupeActiveRows();
    console.log(JSON.stringify(dedupe, null, 2));
  } finally {
    const latest = await pb.collections.getOne(COLLECTION);
    const restoreBase = {
      ...latest,
      listRule: original.listRule,
      viewRule: original.viewRule,
      createRule: original.createRule,
      updateRule: original.updateRule,
      deleteRule: original.deleteRule,
    };
    await restoreRules(restoreBase);
  }

  await applyActiveUniqueIndex();
  console.log('active unique index applied');
}

main().catch((error) => {
  console.error('migration failed', error?.response || error?.message || error);
  process.exitCode = 1;
});
