<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\AttendanceEvent;
use App\Models\Employee;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class PunchController extends Controller
{
    /**
     * POST /api/v1/punches — batch upload of attendance events (idempotent).
     */
    public function store(Request $request)
    {
        $device = $request->attributes->get('device');

        $validator = Validator::make($request->all(), [
            'events' => 'present|array|max:200',
            'events.*.event_uuid' => 'required|string',
            'events.*.emp_id' => 'required|string',
            'events.*.direction' => 'required|in:IN,OUT',
            'events.*.ts' => 'required|string',
            'events.*.confidence' => 'nullable|numeric',
            'events.*.liveness_pass' => 'nullable|boolean',
            'events.*.source' => 'nullable|in:face,manual',
            'events.*.operator' => 'nullable|string',
            'events.*.direction_confidence' => 'nullable|numeric',
            'events.*.corrects_event_uuid' => 'nullable|string',
            'events.*.snapshot_b64' => 'nullable|string',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'error' => [
                    'code' => 'invalid_payload',
                    'message' => $validator->errors()->first(),
                ],
            ], 422);
        }

        $events = $request->input('events', []);

        $accepted = [];
        $duplicate = [];
        $rejected = [];
        $seenInBatch = [];

        foreach ($events as $event) {
            $uuid = $event['event_uuid'];

            if (isset($seenInBatch[$uuid]) || AttendanceEvent::where('event_uuid', $uuid)->exists()) {
                $duplicate[] = $uuid;

                continue;
            }

            $employee = Employee::where('emp_id', $event['emp_id'])->first();

            if (! $employee) {
                $rejected[] = ['event_uuid' => $uuid, 'reason' => 'unknown_emp_id'];

                continue;
            }

            $ts = Carbon::parse($event['ts'])->setTimezone(config('app.timezone'));

            $correctsEvent = null;
            if (! empty($event['corrects_event_uuid'])) {
                $correctsEvent = AttendanceEvent::where('event_uuid', $event['corrects_event_uuid'])->first();
            }

            $snapshotPath = null;
            if (! empty($event['snapshot_b64'])) {
                $snapshotPath = $this->storeSnapshot($event['snapshot_b64'], $uuid, $ts);
            }

            $newEvent = AttendanceEvent::create([
                'event_uuid' => $uuid,
                'employee_id' => $employee->id,
                'device_id' => $device?->id,
                'site_id' => $device?->site_id,
                'direction' => $event['direction'],
                'ts' => $ts,
                'confidence' => $event['confidence'] ?? 0,
                'liveness_pass' => $event['liveness_pass'] ?? true,
                'source' => $event['source'] ?? 'face',
                'operator' => $event['operator'] ?? null,
                'direction_confidence' => $event['direction_confidence'] ?? 0,
                'corrects_event_id' => $correctsEvent?->id,
                'snapshot_path' => $snapshotPath,
            ]);

            if ($correctsEvent) {
                $correctsEvent->update(['corrected_by' => $newEvent->id]);
            }

            $seenInBatch[$uuid] = true;
            $accepted[] = $uuid;
        }

        return response()->json([
            'accepted' => $accepted,
            'duplicate' => $duplicate,
            'rejected' => $rejected,
        ]);
    }

    protected function storeSnapshot(string $base64, string $uuid, Carbon $ts): ?string
    {
        try {
            $data = base64_decode($base64, true);

            if ($data === false) {
                return null;
            }

            $path = 'snapshots/'.$ts->format('Y-m-d').'/'.$uuid.'.jpg';
            Storage::disk('local')->put($path, $data);

            return $path;
        } catch (\Throwable) {
            return null;
        }
    }
}
