<?php

declare(strict_types=1);

namespace Maestro\Core\Modules\HourRegistration\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Maestro\Core\Http\Controllers\Controller;
use Maestro\Core\Modules\HourRegistration\Enums\HourWorkflowStatus;
use Maestro\Core\Modules\HourRegistration\Http\Requests\HourSyncTimesheetWeekRequest;
use Maestro\Core\Modules\HourRegistration\Http\Resources\HourTimesheetWeekResource;
use Maestro\Core\Modules\HourRegistration\Models\HourTimesheetWeek;
use Maestro\Core\Modules\HourRegistration\Services\HourLineSyncService;
use Maestro\Core\Modules\HourRegistration\Services\HourSubmitWeekService;
use Maestro\Core\Modules\HourRegistration\Services\HourTimesheetUnlockService;

class HourTimesheetWeekController extends Controller
{
    public function current(Request $request): HourTimesheetWeekResource
    {
        abort_unless($request->user()?->can('hours.week.manage'), 403);

        $anchor = Carbon::parse($request->query('week_start', Carbon::now()->toDateString()));
        $weekStart = $anchor->copy()->locale('en')->startOfWeek(Carbon::MONDAY);

        $week = HourTimesheetWeek::query()->firstOrCreate([
            'user_id' => $request->user()->getAuthIdentifier(),
            'week_start' => $weekStart->toDateString(),
        ], [
            'workflow_status' => HourWorkflowStatus::Draft,
            'submitted_at' => null,
        ]);

        return new HourTimesheetWeekResource($week->load(['lines.hourTask']));
    }

    public function show(Request $request, HourTimesheetWeek $hour_week): HourTimesheetWeekResource
    {
        abort_unless($request->user(), 403);
        abort_unless(
            $request->user()?->can('hours.admin')
            || ((string) $hour_week->user_id === (string) $request->user()->getAuthIdentifier() && $request->user()?->can('hours.week.manage')),
            403,
        );

        return new HourTimesheetWeekResource($hour_week->load(['lines.hourTask']));
    }

    public function history(Request $request): JsonResponse
    {
        abort_unless($request->user()?->can('hours.week.manage'), 403);

        $perPage = min(max((int) $request->integer('per_page', 15), 1), 100);

        $paginator = HourTimesheetWeek::query()
            ->where('user_id', $request->user()->getAuthIdentifier())
            ->orderByDesc('week_start')
            ->paginate($perPage);

        return HourTimesheetWeekResource::collection($paginator)->response();
    }

    public function sync(HourSyncTimesheetWeekRequest $request, HourTimesheetWeek $hour_week, HourLineSyncService $sync): HourTimesheetWeekResource
    {
        abort_unless((string) $hour_week->user_id === (string) $request->user()->getAuthIdentifier(), 403);

        /** @phpstan-ignore-next-line */
        $validated = $request->validated();

        $weekOut = $sync->syncWeek(
            $hour_week,
            array_values((array) ($validated['lines'] ?? [])),
            array_values((array) ($validated['removed_line_ids'] ?? [])),
        );

        return new HourTimesheetWeekResource($weekOut->load(['lines.hourTask']));
    }

    public function submit(Request $request, HourTimesheetWeek $hour_week, HourSubmitWeekService $submitSvc): JsonResponse
    {
        abort_unless((string) $hour_week->user_id === (string) $request->user()->getAuthIdentifier(), 403);

        $hour_week->load(['lines.hourTask']);

        $result = $submitSvc->submit($hour_week);

        return (new HourTimesheetWeekResource($result['data']->loadMissing(['lines.hourTask'])))
            ->additional(['warnings' => $result['warnings']])
            ->response();
    }

    public function unlock(Request $request, HourTimesheetWeek $hour_week, HourTimesheetUnlockService $unlock): HourTimesheetWeekResource
    {
        abort_unless($request->user()?->can('hours.admin'), 403);

        $fresh = $unlock->unlock($hour_week);

        return new HourTimesheetWeekResource($fresh->load(['lines.hourTask']));
    }
}
