<?php

namespace App\Services\System;

use Carbon\CarbonImmutable;
use DateTimeInterface;

class TimeService
{
    public function userTimezone(): string
    {
        $schoolConfig = config('School');
        if (is_object($schoolConfig) && isset($schoolConfig->attendance['timezone'])) {
            return (string) $schoolConfig->attendance['timezone'];
        }
        if (is_array($schoolConfig) && isset($schoolConfig['attendance']['timezone'])) {
            return (string) $schoolConfig['attendance']['timezone'];
        }

        return (string) (config('app.timezone') ?: 'UTC');
    }

    public function primeFromRequest($request): void
    {
        $headerTz = (string) ($request?->header('X-Timezone') ?? '');
        if ($headerTz === '') {
            $headerTz = (string) ($request?->header('Time-Zone') ?? '');
        }

        if ($headerTz !== '' && in_array($headerTz, \DateTimeZone::listIdentifiers(), true)) {
            // No session-backed storage; header is read per request if needed.
        }
    }

    public function serverTimezone(): string
    {
        return (string) (config('app.timezone') ?: 'UTC');
    }

    public function nowUtc(): CarbonImmutable
    {
        return CarbonImmutable::now('UTC');
    }

    public function nowLocal(?string $tz = null): CarbonImmutable
    {
        return CarbonImmutable::now($tz ?: $this->userTimezone());
    }

    public function toUtc($value, ?string $fromTz = null, string $format = 'Y-m-d H:i:s'): ?string
    {
        $dt = $this->parse($value, $fromTz);
        if (!$dt) {
            return null;
        }

        return $dt->setTimezone('UTC')->format($format);
    }

    public function toLocal($value, ?string $sourceTz = null, ?string $targetTz = null, string $format = 'Y-m-d H:i:s'): ?string
    {
        $dt = $this->parse($value, $sourceTz);
        if (!$dt) {
            return null;
        }

        return $dt->setTimezone($targetTz ?: $this->userTimezone())->format($format);
    }

    public function formatLocal($value, string $format = 'Y-m-d', ?string $sourceTz = null): string
    {
        $dt = $this->parse($value, $sourceTz);
        if (!$dt) {
            return '';
        }

        return $dt->setTimezone($this->userTimezone())->format($format);
    }

    private function parse($value, ?string $tz = null): ?CarbonImmutable
    {
        if ($value instanceof DateTimeInterface) {
            return CarbonImmutable::instance($value);
        }

        $raw = trim((string) $value);
        if ($raw === '') {
            return null;
        }

        try {
            return CarbonImmutable::parse($raw, $tz ?: $this->serverTimezone());
        } catch (\Throwable $e) {
            return null;
        }
    }
}
