<?php

namespace App\Console\Commands;

use App\Models\AttendancePunch;
use App\Models\BiometricDevice;
use App\Services\Biometric\BiometricFirstInLastOutService;
use App\Services\Biometric\ZktecoPunchIngestService;
use Carbon\Carbon;
use Illuminate\Console\Command;

class RecalculateFiloBiometricAttendance extends Command
{
    protected $signature = 'zkteco:recalculate-filo
                            {--company_id= : Limit to one company}
                            {--from= : Start date Y-m-d (inclusive)}
                            {--to= : End date Y-m-d (inclusive)}
                            {--dry-run : Show days that would be recalculated}';

    protected $description = 'Recalculate First-IN/Last-OUT attendance for both-mode biometric devices';

    public function handle(
        BiometricFirstInLastOutService $filoService,
        ZktecoPunchIngestService $ingestService
    ): int {
        $companyId = $this->option('company_id');
        $from = $this->option('from')
            ? Carbon::createFromFormat('Y-m-d', $this->option('from'))->startOfDay()
            : null;
        $to = $this->option('to')
            ? Carbon::createFromFormat('Y-m-d', $this->option('to'))->endOfDay()
            : null;
        $dryRun = (bool) $this->option('dry-run');

        $deviceQuery = BiometricDevice::withoutGlobalScopes()
            ->where(function ($q) {
                $q->where('punch_mode', BiometricDevice::PUNCH_MODE_BOTH)
                    ->orWhereNull('punch_mode');
            });
        if ($companyId !== null && $companyId !== '') {
            $deviceQuery->where('company_id', (int) $companyId);
        }
        $deviceIds = $deviceQuery->pluck('id');

        if ($deviceIds->isEmpty()) {
            $this->warn('No both-mode biometric devices found.');

            return self::SUCCESS;
        }

        $punchQuery = AttendancePunch::withoutGlobalScopes()
            ->whereIn('biometric_device_id', $deviceIds)
            ->whereNotNull('emp_code');
        if ($companyId !== null && $companyId !== '') {
            $punchQuery->where('company_id', (int) $companyId);
        }
        if ($from) {
            $punchQuery->where('punch_datetime', '>=', $from->format('Y-m-d H:i:s'));
        }
        if ($to) {
            $punchQuery->where('punch_datetime', '<=', $to->format('Y-m-d H:i:s'));
        }

        $ids = $punchQuery->orderBy('punch_datetime')->orderBy('id')->pluck('id');
        $this->info('Processing '.$ids->count().' punch(es) from both-mode devices...');

        if ($dryRun) {
            $this->line('Dry run only — no writes.');

            return self::SUCCESS;
        }

        $days = [];
        foreach ($ids as $id) {
            $ingestService->applyPunch((int) $id);
            $punch = AttendancePunch::withoutGlobalScopes()->find($id);
            if ($punch?->user_id && $punch->attendance_date) {
                $key = $punch->company_id.'|'.$punch->user_id.'|'.$punch->attendance_date->format('Y-m-d');
                $days[$key] = [
                    'company_id' => (int) $punch->company_id,
                    'user_id' => (int) $punch->user_id,
                    'date' => $punch->attendance_date->format('Y-m-d'),
                ];
            }
        }

        foreach ($days as $day) {
            $filoService->recalculateEmployeeAttendance(
                $day['company_id'],
                $day['user_id'],
                $day['date']
            );
        }

        $this->info('Recalculated '.count($days).' employee-day(s).');

        return self::SUCCESS;
    }
}
