import path from 'path';
import connectToDatabase from '@/shared/config/dbConfig';
import {
  getCellSafe,
  normalizeHeader,
  readExcelFile,
  toNumberSafe,
} from '../helpers/excel-data';
import Area from '@/modules/master/location/area/area.model';
import City from '@/modules/master/location/city/city.model';
import State from '@/modules/master/location/state/state.model';
import Country from '@/modules/master/location/country/country.model';

const __dirname = path.resolve();

const FILE_PATH = path.join(__dirname, 'src/scripts/area/delhi_areas.xlsx');
const DELHI_COORDS: [number, number] = [77.1025, 28.7041]; // [lon, lat]

(async () => {
  try {
    await connectToDatabase();
    console.log('✅ Connected to MongoDB');

    const rows = readExcelFile(FILE_PATH);
    if (!rows || rows.length === 0) {
      console.error('No rows found in Excel file. Exiting.');
      process.exit(1);
    }
    console.log(`Read ${rows.length} rows from Excel.`);

    const sampleHeaders = Object.keys(rows[0]);
    const keyList = sampleHeaders;

    function findKey(patterns: string[]) {
      for (const k of keyList) {
        const nk = normalizeHeader(k);
        for (const pat of patterns) if (nk.includes(pat)) return k;
      }
      return undefined;
    }

    const headerMap = {
      area: findKey(['area']),
      pincode: findKey(['pincode']),
      city: findKey(['city']),
      state: findKey(['state']),
      lat: findKey(['latitude']),
      lon: findKey(['longitude']),
    };


    const countryDoc = await Country.findOne({ name: 'india' });
    if (!countryDoc) throw new Error('Country "India" not found');
    console.log('Country ensured:', countryDoc.name);

    const uniqueCities = new Map<string, string>();

    const defaultStateName = 'delhi';
    const sDoc = await State.findOneAndUpdate(
      { name: defaultStateName },
      {
        $setOnInsert: {
          name: defaultStateName,
          country: countryDoc._id,
          loc: { type: 'Point', coordinates: DELHI_COORDS },
        },
      },
      { upsert: true, new: true },
    );
    console.log('🚀 ~ sDoc:', sDoc);
    console.log('No state detected — created default state:', defaultStateName);

    const cityDocsArray = await Promise.all(
      Array.from(uniqueCities.entries()).map(async ([cityName]) => {
        const cDoc = await City.findOneAndUpdate(
          { name: cityName },
          {
            $setOnInsert: {
              name: cityName,
              state: sDoc._id,
              loc: { type: 'Point', coordinates: DELHI_COORDS },
            },
          },
          { upsert: true, new: true },
        );
        console.log(`City ensured: ${cityName} (state: ${defaultStateName})`);
        return [cityName, cDoc] as const;
      }),
    );

    const cityNameToDoc = new Map(
      cityDocsArray.filter(Boolean) as [string, any][],
    );

    const areaChunks = [];
    const CHUNK_SIZE = 100;
    for (let i = 0; i < rows.length; i += CHUNK_SIZE)
      areaChunks.push(rows.slice(i, i + CHUNK_SIZE));

    let processedCount = 0;
    const totalCount = rows.length;
    /* eslint-disable no-await-in-loop */
    for (const chunk of areaChunks)
      await Promise.all(
        chunk.map(async (row) => {
          const rawArea = String(
            getCellSafe(row, headerMap.area || '') || '',
          ).trim();
          const rawPincode = String(
            getCellSafe(row, headerMap.pincode || '') || '',
          ).trim();
          const rawCity = String(
            getCellSafe(row, headerMap.city || '') || '',
          ).trim();

          const latVal = toNumberSafe(getCellSafe(row, headerMap.lat || ''));
          const lonVal = toNumberSafe(getCellSafe(row, headerMap.lon || ''));
          const coords: [number, number] =
            latVal !== null && lonVal !== null
              ? [lonVal, latVal]
              : DELHI_COORDS;

          let cityDoc = cityNameToDoc.get(rawCity);
          if (!cityDoc) {
            cityDoc = await City.findOneAndUpdate(
              { name: rawCity },
              {
                $setOnInsert: {
                  name: rawCity,
                  state: sDoc._id,
                  loc: { type: 'Point', coordinates: DELHI_COORDS },
                },
              },
              { upsert: true, new: true },
            );
            cityNameToDoc.set(rawCity, cityDoc);
            console.log(`Created (on-the-fly) city: ${rawCity}`);
          }

          const pincodeNum = toNumberSafe(rawPincode);
          const query: any = { name: rawArea, city: cityDoc?._id };
          const update: any = {
            $set: {
              name: rawArea,
              city: cityDoc?._id,
              loc: { type: 'Point', coordinates: coords },
            },
          };
          if (pincodeNum !== null) update.$addToSet = { pinCode: pincodeNum };

          await Area.findOneAndUpdate(query, update, {
            upsert: true,
            new: true,
          });

          processedCount++;
          if (processedCount % 50 === 0 || processedCount === totalCount) {
            const percent = ((processedCount / totalCount) * 100).toFixed(1);
            process.stdout.write(
              `Progress: ${processedCount}/${totalCount} (${percent}%)\r`,
            );
          }
        }),
      );

    console.log('\n✅ Seeding complete.');
    process.exit(0);
  } catch (error) {
    console.error('❌ Error during seeding:', error);
    process.exit(1);
  }
})();
