<?php

namespace App\Services;

use Carbon\Carbon;

class NaturalTimestampService
{
    /**
     * Generate created_at timestamp aligned with check-in time
     */
    public function generateCreatedAt(Carbon $checkInTime): Carbon
    {
        return $checkInTime->copy()->addSeconds(rand(0, 120));
    }

    /**
     * Generate natural check-in time based on work hours
     */
    public function generateNaturalCheckInTime(Carbon $date, ?string $requestedTime = null): Carbon
    {
        if ($requestedTime) {
            $base = Carbon::parse($date->format('Y-m-d') . ' ' . $requestedTime);
        } else {
            $baseHour = 8;
            $baseMinute = rand(-15, 15);
            $base = Carbon::parse($date->format('Y-m-d'))
                ->setHour($baseHour)
                ->setMinute($baseMinute < 0 ? 60 + $baseMinute : $baseMinute);
            if ($baseMinute < 0) {
                $base->subHour();
            }
        }

        return $base->addSeconds(rand(0, 59));
    }

    /**
     * Generate natural check-out time based on work duration
     */
    public function generateNaturalCheckOutTime(Carbon $checkInTime): Carbon
    {
        $workHours = rand(8, 9);
        $extraMinutes = rand(-30, 60);

        return $checkInTime->copy()
            ->addHours($workHours)
            ->addMinutes($extraMinutes)
            ->addSeconds(rand(0, 59));
    }

    /**
     * Normalize coordinate precision
     */
    public function normalizeCoordinate(float $coord, int $decimals = 6): float
    {
        return round($coord, $decimals);
    }

    /**
     * Add GPS coordinate variation for realistic positioning
     *
     * @param float $lat Latitude
     * @param float $lon Longitude
     * @param bool $useSmallRadius If true, use smaller radius (10-20m), otherwise use 10-50m
     * @return array
     */
    public function addNaturalCoordinateVariation(float $lat, float $lon, bool $useSmallRadius = false): array
    {
        if ($useSmallRadius) {
            $minVariation = 9;
            $maxVariation = 18;
        } else {
            $minVariation = 9;
            $maxVariation = 45;
        }

        $latVariation = (rand($minVariation, $maxVariation) / 100000) * (rand(0, 1) ? 1 : -1);
        $lonVariation = (rand($minVariation, $maxVariation) / 100000) * (rand(0, 1) ? 1 : -1);

        return [
            'latitude' => round($lat + $latVariation, 6),
            'longitude' => round($lon + $lonVariation, 6),
        ];
    }

    /**
     * Spread timestamps for batch processing
     */
    public function spreadBatchTimestamps(array $attendanceDates): array
    {
        $timestamps = [];

        foreach ($attendanceDates as $date) {
            $checkInTime = $this->generateNaturalCheckInTime(Carbon::parse($date));
            $createdAt = $this->generateCreatedAt($checkInTime);

            while (in_array($createdAt->timestamp, array_column($timestamps, 'created_timestamp'))) {
                $createdAt->addSeconds(rand(1, 60));
            }

            $timestamps[] = [
                'date' => $date,
                'check_in_time' => $checkInTime,
                'created_at' => $createdAt,
                'created_timestamp' => $createdAt->timestamp,
            ];
        }

        return $timestamps;
    }

    /**
     * Generate timestamps based on company settings
     */
    public function generateTimestamps(
        Carbon $attendanceDate,
        ?string $checkInTime = null,
        ?string $checkOutTime = null,
        bool $normalizeEnabled = true
    ): array {
        $today = Carbon::today();
        $isPastDate = $attendanceDate->lt($today);

        if ($normalizeEnabled && $isPastDate) {
            $naturalCheckIn = $this->generateNaturalCheckInTime($attendanceDate, $checkInTime);
            $naturalCreatedAt = $this->generateCreatedAt($naturalCheckIn);

            $naturalCheckOut = null;
            if ($checkOutTime) {
                $naturalCheckOut = Carbon::parse($attendanceDate->format('Y-m-d') . ' ' . $checkOutTime)
                    ->addSeconds(rand(0, 59));
            }

            return [
                'check_in_time' => $naturalCheckIn,
                'check_out_time' => $naturalCheckOut,
                'created_at' => $naturalCreatedAt,
                'updated_at' => $naturalCreatedAt,
            ];
        }

        $now = Carbon::now();
        $naturalCheckIn = $checkInTime
            ? Carbon::parse($attendanceDate->format('Y-m-d') . ' ' . $checkInTime)->addSeconds(rand(0, 59))
            : $now;

        $naturalCheckOut = null;
        if ($checkOutTime) {
            $naturalCheckOut = Carbon::parse($attendanceDate->format('Y-m-d') . ' ' . $checkOutTime)
                ->addSeconds(rand(0, 59));
        }

        return [
            'check_in_time' => $naturalCheckIn,
            'check_out_time' => $naturalCheckOut,
            'created_at' => $now,
            'updated_at' => $now,
        ];
    }
}
