<?php

namespace App\Console\Commands;

use App\Models\Attendance;
use App\Models\Location;
use App\Models\SuratTugas;
use Illuminate\Console\Command;

class FixBpkpCoordinates extends Command
{
    protected $signature = 'attendance:fix-bpkp-coordinates
                            {--dry-run : Show what would be updated without making changes}
                            {--location= : Location ID or name to use as center point (optional, auto-detect from locations table)}';

    protected $description = 'Fix BPKP Pusat/Office/Kantor coordinates to be within proper area (5-30m radius)';

    public function handle()
    {
        $dryRun = $this->option('dry-run');
        $locationOption = $this->option('location');

        $this->info("BPKP Coordinates Fixer");
        $this->info("======================");

        // Get center coordinates from locations table
        $location = $this->findCenterLocation($locationOption);

        if (!$location) {
            $this->error("Could not find a valid location for center coordinates.");
            $this->info("Please specify a location using --location=<id or name>");
            $this->info("\nAvailable internal locations:");
            $this->listAvailableLocations();
            return 1;
        }

        $centerLat = (float) $location->latitude;
        $centerLon = (float) $location->longitude;

        $this->info("Using location: {$location->name}");
        $this->info("Center point: {$centerLat}, {$centerLon}");
        $this->info("Radius: 5-30 meters");

        if ($dryRun) {
            $this->warn("\n[DRY RUN MODE - No changes will be made]\n");
        }

        // Find attendances with BPKP Pusat/Office/Kantor in address
        $attendances = Attendance::where(function ($q) {
            $q->where('check_in_address', 'like', '%BPKP Pusat%')
              ->orWhere('check_in_address', 'like', '%bpkp pusat%')
              ->orWhere('check_in_address', 'like', '%Office%')
              ->orWhere('check_in_address', 'like', '%office%')
              ->orWhere('check_in_address', 'like', '%Kantor%')
              ->orWhere('check_in_address', 'like', '%kantor%')
              ->orWhere('check_in_address', 'like', '%Headquarter%')
              ->orWhere('check_in_address', 'like', '%headquarter%')
              ->orWhere('check_in_address', 'like', '%HQ%');
        })
        ->whereNotNull('check_in_latitude')
        ->whereNotNull('check_in_longitude')
        ->get();

        $this->info("Found {$attendances->count()} attendance records to update.\n");

        if ($attendances->isEmpty()) {
            $this->info("No records to update.");
            return 0;
        }

        // Show sample of records to be updated
        $this->info("Sample records:");
        $this->table(
            ['ID', 'User ID', 'Date', 'Address', 'Current Lat', 'Current Lon'],
            $attendances->take(10)->map(fn ($a) => [
                $a->id,
                $a->user_id,
                $a->date->format('Y-m-d'),
                \Illuminate\Support\Str::limit($a->check_in_address, 30),
                $a->check_in_latitude,
                $a->check_in_longitude,
            ])
        );

        if ($attendances->count() > 10) {
            $this->info("... and " . ($attendances->count() - 10) . " more records.\n");
        }

        if (!$dryRun) {
            if (!$this->confirm("Do you want to proceed with updating {$attendances->count()} records?")) {
                $this->info("Operation cancelled.");
                return 0;
            }
        }

        $bar = $this->output->createProgressBar($attendances->count());
        $bar->start();

        $updated = 0;
        foreach ($attendances as $attendance) {
            // Generate new random coordinates within 5-15m radius
            $checkinOffset = SuratTugas::applyRandomOffset($centerLat, $centerLon);

            $updateData = [
                'check_in_latitude' => $checkinOffset['latitude'],
                'check_in_longitude' => $checkinOffset['longitude'],
            ];

            // Also update checkout coordinates if they exist
            if ($attendance->check_out_latitude && $attendance->check_out_longitude) {
                $checkoutOffset = SuratTugas::applyRandomOffset($centerLat, $centerLon);
                $updateData['check_out_latitude'] = $checkoutOffset['latitude'];
                $updateData['check_out_longitude'] = $checkoutOffset['longitude'];
            }

            if (!$dryRun) {
                // Use query builder to avoid touching timestamps
                Attendance::where('id', $attendance->id)->update($updateData);
            }

            $updated++;
            $bar->advance();
        }

        $bar->finish();
        $this->newLine(2);

        if ($dryRun) {
            $this->info("Would have updated {$updated} records.");
            $this->warn("Run without --dry-run to actually make changes.");
        } else {
            $this->info("Successfully updated {$updated} records.");
        }

        // Show sample of updated coordinates
        $this->newLine();
        $this->info("Sample of new coordinates (random within 5-30m radius):");
        for ($i = 0; $i < 5; $i++) {
            $sample = SuratTugas::applyRandomOffset($centerLat, $centerLon);
            $this->line("  - {$sample['latitude']}, {$sample['longitude']}");
        }

        return 0;
    }

    /**
     * Find center location from database
     * Priority: 1. By ID/name if provided, 2. Auto-detect headquarters/BPKP location
     */
    private function findCenterLocation(?string $locationOption): ?Location
    {
        // If location option is provided, try to find by ID or name
        if ($locationOption) {
            // Try by ID first
            if (is_numeric($locationOption)) {
                $location = Location::find($locationOption);
                if ($location && $location->latitude && $location->longitude) {
                    return $location;
                }
            }

            // Try by name (partial match)
            $location = Location::where('name', 'like', "%{$locationOption}%")
                ->whereNotNull('latitude')
                ->whereNotNull('longitude')
                ->first();

            if ($location) {
                return $location;
            }

            return null;
        }

        // Auto-detect: Look for headquarters or BPKP Pusat location
        // Priority 1: Type headquarters
        $location = Location::where('type', 'headquarters')
            ->whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->where('is_active', true)
            ->first();

        if ($location) {
            return $location;
        }

        // Priority 2: Name contains BPKP Pusat
        $location = Location::where('name', 'like', '%BPKP Pusat%')
            ->whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->where('is_active', true)
            ->first();

        if ($location) {
            return $location;
        }

        // Priority 3: Primary internal location
        $location = Location::where('is_primary', true)
            ->where('category', 'internal')
            ->whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->where('is_active', true)
            ->first();

        if ($location) {
            return $location;
        }

        // Priority 4: Any internal location with allow_daily_checkin
        $location = Location::where('category', 'internal')
            ->where('allow_daily_checkin', true)
            ->whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->where('is_active', true)
            ->first();

        return $location;
    }

    /**
     * List available locations for selection
     */
    private function listAvailableLocations(): void
    {
        $locations = Location::whereNotNull('latitude')
            ->whereNotNull('longitude')
            ->where('is_active', true)
            ->orderBy('is_primary', 'desc')
            ->orderBy('category')
            ->orderBy('name')
            ->get(['id', 'name', 'type', 'category', 'latitude', 'longitude']);

        if ($locations->isEmpty()) {
            $this->warn("No locations found in database.");
            return;
        }

        $this->table(
            ['ID', 'Name', 'Type', 'Category', 'Latitude', 'Longitude'],
            $locations->map(fn ($loc) => [
                $loc->id,
                \Illuminate\Support\Str::limit($loc->name, 40),
                $loc->type,
                $loc->category,
                $loc->latitude,
                $loc->longitude,
            ])
        );
    }
}
