import { locations, PrismaClient, unit_type, units } from '@prisma/client';
import * as XLSX from 'xlsx';
import * as fs from 'fs';
import * as path from 'path';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { createClient } from '../../app/_utils/supabase/client';
import { generateId, generateIdWithDbCounter } from '../../app/_utils/common';

// Interface untuk data Excel row
interface ExcelRow {
  KESATUAN: string;
  [key: string]: any; // Untuk kolom dinamis seperti "JAN CT", "JAN CC", dll
}

// Interface untuk mapping bulan
interface MonthMap {
  [key: string]: number;
}

// Interface untuk statistik unit
interface UnitStatistics {
  unit_id: string;
  month: number;
  year: number;
  crime_total: number;
  crime_cleared: number;
  percentage: number;
  pending: number;
}

interface CreateLocationDto {
  district_id: string;
  code_unit: string;
  city_id: string;
  name?: string;
  description?: string;
  address?: string;
  type?: string;
  phone?: string;
  latitude: number;
  longitude: number;
  land_area?: number;
  polygon?: Record<string, any>;
  geometry?: Record<string, any>;
  location?: string;
}

export class UnitSeeder {
  private mapboxToken: string;

  constructor(
    private prisma: PrismaClient,
    private supabase = createClient()
  ) {
    this.mapboxToken = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN || '';
  }

  async run(): Promise<void> {
    await this.prisma.units.deleteMany({});

    const districts = await this.prisma.districts.findMany({
      include: {
        cities: true,
      },
    });

    const city = await this.prisma.cities.findFirst({
      where: {
        name: 'Jember',
      },
      include: {
        districts: true,
      },
    });

    if (!city) {
      console.error('City not found: Jember');
      return;
    }

    const location = await this.getUnitsLocation(city.name);

    if (!location) {
      console.warn(`No location found for city: ${city.name}`);
      return;
    }

    const [lng, lat] = [location.lng, location.lat];
    const address = location.address;
    const phone = location.telepon?.replace(/-/g, '');

    const newId = await generateIdWithDbCounter('units', {
      prefix: 'UT',
      segments: {
        sequentialDigits: 4,
      },
      format: '{prefix}-{sequence}',
      separator: '-',
      uniquenessStrategy: 'counter',
    });

    let locationData: CreateLocationDto = {
      district_id: city.districts[0].id, // This will be replaced with Patrang's ID
      city_id: city.id,
      code_unit: newId,
      name: `Polres ${city.name}`,
      description: `Unit ${city.name} is categorized as POLRES and operates in the ${city.name} area.`,
      type: 'polres',
      address,
      phone,
      longitude: lng,
      latitude: lat,
      location: `POINT(${lng} ${lat})`,
    };

    // Find the Patrang district
    const patrangDistrict = await this.prisma.districts.findFirst({
      where: {
        name: 'Patrang',
        city_id: city.id,
      },
    });

    if (!patrangDistrict) {
      console.error('District not found: Patrang');
      return;
    }

    locationData.district_id = patrangDistrict.id;

    const { error } = await this.supabase
      .from('units')
      .insert([locationData])
      .select();

    if (error) {
      console.error(`Error inserting into Supabase locations:`, error);
      return;
    }

    let district;

    for (district of districts) {
      const location = await this.getUnitsLocation(district.name);

      if (!location) {
        console.warn(`No location found for district: ${district.name}`);
        continue;
      }

      const [lng, lat] = [location.lng, location.lat];
      const address = location.address;
      const phone = location.telepon?.replace(/-/g, '');

      const newId = await generateIdWithDbCounter('units', {
        prefix: 'UT',
        segments: {
          sequentialDigits: 4,
        },
        format: '{prefix}-{sequence}',
        separator: '-',
        uniquenessStrategy: 'counter',
      });

      const locationData: CreateLocationDto = {
        district_id: district.id,
        city_id: district.city_id,
        code_unit: newId,
        name: `Polsek ${district.name}`,
        description: `Unit ${district.name} is categorized as POLSEK and operates in the ${district.name} area.`,
        type: 'polsek',
        address: address,
        phone,
        longitude: lng,
        latitude: lat,
        location: `POINT(${lng} ${lat})`,
      };

      const { error } = await this.supabase
        .from('units')
        .insert([locationData])
        .select();

      if (error) {
        console.error(`Error inserting into Supabase locations:`, error);
        continue;
      }

      console.log(
        `Inserted unit for district: ${district.name}, newId: ${newId} at ${lng}, ${lat}`
      );
    }
  }

  private parseNumber(value: any): number {
    if (value === undefined || value === null) return 0;
    const num = Number(value);
    return isNaN(num) ? 0 : num;
  }

  private async getUnitsLocation(districtName: string): Promise<{
    lng: number;
    lat: number;
    address: string;
    telepon: string;
  } | null> {
    // const getCoordinatesFromMapbox = async (
    //   query: string
    // ): Promise<{ lng: number; lat: number } | null> => {
    //   const suggestUrl = `https://api.mapbox.com/search/searchbox/v1/suggest?q=${encodeURIComponent(
    //     query
    //   )}&session_token=${uuidv4()}&access_token=${this.mapboxToken}`;

    //   // console.log(`Suggest URL: ${suggestUrl}`);

    //   const res = await axios.get(suggestUrl);
    //   const suggestions = res?.data?.suggestions;

    //   if (!suggestions || suggestions.length === 0) return null;

    //   const mapboxId = suggestions[0].mapbox_id;

    //   // console.log(`Mapbox ID for ${query}: ${mapboxId}`);

    //   if (!mapboxId) return null;

    //   const retrieveUrl = `https://api.mapbox.com/search/searchbox/v1/retrieve/${mapboxId}?session_token=${uuidv4()}&access_token=${this.mapboxToken}`;

    //   // console.log(`Retrieve URL: ${retrieveUrl}`);

    //   const retrieveResponse = await axios.get(retrieveUrl);
    //   const features = retrieveResponse?.data.features;

    //   const [lng, lat] = features[0].geometry.coordinates;

    //   return { lng, lat };
    // };

    // Buka file Excel untuk ambil data nama dan alamat Polsek
    const fallbackFilePath = path.join(
      __dirname,
      '../data/excels/administrations/polsek_jember.xlsx'
    );

    const workbook = XLSX.readFile(fallbackFilePath);
    const sheetName = workbook.SheetNames[0];
    const sheet = workbook.Sheets[sheetName];
    const rows = XLSX.utils.sheet_to_json(sheet) as {
      'Nama Unit': string;
      Alamat: string;
      Telepon: string;
      lat: number;
      long: number;
    }[];

    // Temukan Polsek berdasarkan kecamatan (nama kecamatan ada dalam alamat)
    const matchedRow = rows.find(
      (row) =>
        row.Alamat?.toLowerCase().includes(districtName.toLowerCase()) ||
        row['Nama Unit'].toLowerCase().includes(districtName.toLowerCase())
    );

    // console.log(`Matched row for ${districtName}:`, matchedRow);

    if (!matchedRow) {
      console.warn(
        `No matching Polsek found in sheet for district: ${districtName}`
      );
      return null;
    }

    const polsekName = matchedRow['Nama Unit'];
    const polsekAddress = matchedRow.Alamat;
    const telepon = matchedRow.Telepon;
    const coordinates = {
      lng: matchedRow.long,
      lat: matchedRow.lat,
    };

    // Ambil koordinat dari Mapbox, tapi alamat tetap pakai dari sheet
    // const coordinates = await getCoordinatesFromMapbox(polsekName);

    // if (!coordinates) {
    //   console.warn(`Mapbox couldn't find coordinates for: ${polsekName}`);
    //   return null;
    // }

    // console.log(
    //   `Coordinates for ${polsekName} (${districtName}): ${coordinates.lng}, ${coordinates.lat}`
    // );

    console.log(
      `Polsek Name: ${polsekName}, Address: ${polsekAddress}, Telepon: ${telepon}`
    );

    return {
      ...coordinates,
      telepon,
      address: polsekAddress, // ambil dari sheet, bukan dari Mapbox
    };
  }
}
