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; name?: string; description?: string; address?: string; type?: string; phone?: string; latitude: number; longitude: number; land_area?: number; polygon?: Record; geometry?: Record; 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 { 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 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, 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 }; } }