<?php

declare(strict_types=1);

namespace Maestro\Core\Modules\HourRegistration\Services;

use Carbon\Carbon;
use Illuminate\Contracts\Auth\Authenticatable;
use Maestro\Core\Modules\HourRegistration\Enums\HourLineApprovalStatus;
use Maestro\Core\Modules\HourRegistration\Enums\HourRegistrationType;
use Maestro\Core\Modules\HourRegistration\Enums\HourWorkflowStatus;
use Maestro\Core\Modules\HourRegistration\Models\HourTimesheetLine;

final class HourReportSummaryService
{
    public function __construct(
        private readonly HourTotalsCalculator $totalsCalculator,
    ) {}

    /**
     * @param  array{from:?string,to:?string,group?:string,user_id?:int|string|null}  $params
     * @return array<string, mixed>
     */
    public function summarize(Authenticatable $user, array $params): array
    {
        abort_unless($user->can('hours.reports.view') || $user->can('hours.admin'), 403);

        $from = (($params['from'] ?? null) !== null && $params['from'] !== '')
            ? Carbon::parse((string) $params['from'])->startOfDay()
            : Carbon::now()->subMonthsNoOverflow(3)->startOfDay();

        $to = (($params['to'] ?? null) !== null && $params['to'] !== '')
            ? Carbon::parse((string) $params['to'])->endOfDay()
            : Carbon::now()->endOfDay();

        $groupBy = (string) ($params['group'] ?? 'month');
        if ($groupBy !== 'week' && $groupBy !== 'month') {
            $groupBy = 'month';
        }

        /** @phpstan-ignore-next-line */
        $scopedUserId = isset($params['user_id']) && $params['user_id'] !== '' ? (int) $params['user_id'] : null;

        $byCustomer = [];
        $byProject = [];

        $query = HourTimesheetLine::query()
            ->with(['week', 'hourProject'])
            ->where('line_approval_status', HourLineApprovalStatus::Approved)
            ->whereHas('week', function ($w) use ($from, $to, $scopedUserId): void {
                $w->where('workflow_status', HourWorkflowStatus::Approved)
                    ->whereDate('week_start', '>=', $from->toDateString())
                    ->whereDate('week_start', '<=', $to->toDateString());
                if ($scopedUserId !== null) {
                    $w->where('user_id', $scopedUserId);
                }
            });

        foreach ($query->lazy(100) as $line) {
            $week = $line->week;
            if ($week === null) {
                continue;
            }

            /** @phpstan-ignore-next-line */
            $wk = Carbon::parse($week->week_start->format('Y-m-d'));
            $periodKey = $groupBy === 'week'
                ? sprintf('%s-W%02d', $wk->format('o'), (int) $wk->format('W'))
                : $wk->format('Y-m');

            $hrs = $this->totalsCalculator->lineTotalHours($line);

            if ($line->registration_type === HourRegistrationType::Customer && $line->customer_id !== null) {
                $idx = "{$periodKey}|".$line->customer_id;
                if (! isset($byCustomer[$idx])) {
                    $byCustomer[$idx] = ['period_key' => $periodKey, 'customer_id' => (int) $line->customer_id, 'total_hours' => 0.0];
                }
                $byCustomer[$idx]['total_hours'] = round($byCustomer[$idx]['total_hours'] + $hrs, 2);
            }

            if (($line->hour_project_id ?? null) !== null) {
                $line->loadMissing('hourProject');
                /** @phpstan-ignore-next-line */
                $projName = $line->hourProject?->name ?? '—';
                $idx = "{$periodKey}|".$line->hour_project_id;
                if (! isset($byProject[$idx])) {
                    $byProject[$idx] = ['period_key' => $periodKey, 'project_id' => (int) $line->hour_project_id, 'project_name' => $projName, 'total_hours' => 0.0];
                }
                $byProject[$idx]['total_hours'] = round($byProject[$idx]['total_hours'] + $hrs, 2);
            }
        }

        return [
            'group_by' => $groupBy,
            'period' => ['from' => $from->toDateString(), 'to' => $to->toDateString()],
            'by_customer' => array_values($byCustomer),
            'by_project' => array_values($byProject),
        ];
    }
}
