<?php

namespace App\Modules\HR\Recruitment\Services;

use App\Modules\HR\Recruitment\DTOs\RecruitmentReportFilters;
use App\Modules\HR\Recruitment\Repositories\RecruitmentReportRepository;
use App\Modules\HR\Recruitment\Support\ApplicationStatus;
use App\Modules\HR\Recruitment\Support\InterviewStatus;
use App\Modules\HR\Recruitment\Support\OfferLetterStatus;
use App\Modules\HR\Recruitment\Support\VacancyStatus;
use Carbon\Carbon;

class RecruitmentReportDashboardService
{
    public function __construct(
        private readonly RecruitmentReportRepository $reports,
    ) {}

    /** @return array<string, int|float> */
    public function cards(int $tenantId, ?RecruitmentReportFilters $filters = null): array
    {
        $f = $filters ?? new RecruitmentReportFilters;
        $openVac = $this->reports->vacanciesBase($tenantId, new RecruitmentReportFilters(
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
            status: VacancyStatus::OPEN,
        ))->count();

        $activeApps = $this->reports->applicationsBase($tenantId, new RecruitmentReportFilters(
            dateFrom: $f->dateFrom,
            dateTo: $f->dateTo,
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
        ))->whereNotIn('status', [ApplicationStatus::REJECTED, ApplicationStatus::WITHDRAWN, ApplicationStatus::HIRED])->count();

        $interviews = $this->reports->interviewsBase($tenantId, new RecruitmentReportFilters(
            dateFrom: $f->dateFrom,
            dateTo: $f->dateTo,
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
            status: InterviewStatus::SCHEDULED,
        ))->count();

        $offersPending = $this->reports->offersBase($tenantId, new RecruitmentReportFilters(
            dateFrom: $f->dateFrom,
            dateTo: $f->dateTo,
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
            status: OfferLetterStatus::SENT,
        ))->count();

        $monthFrom = $f->dateFrom ?? Carbon::now()->startOfMonth()->toDateString();
        $monthTo = $f->dateTo ?? Carbon::now()->toDateString();
        $hires = $this->reports->hiringsBase($tenantId, new RecruitmentReportFilters(
            dateFrom: $monthFrom,
            dateTo: $monthTo,
            departmentId: $f->departmentId,
            vacancyId: $f->vacancyId,
            recruiterId: $f->recruiterId,
        ))->count();

        $avgDays = $this->avgTimeToHire($tenantId, $f);

        return [
            'open_vacancies' => $openVac,
            'active_applications' => $activeApps,
            'scheduled_interviews' => $interviews,
            'offers_pending' => $offersPending,
            'hires_period' => $hires,
            'avg_time_to_hire' => $avgDays,
        ];
    }

    private function avgTimeToHire(int $tenantId, RecruitmentReportFilters $f): float
    {
        $apps = $this->reports->applicationsBase($tenantId, $f)
            ->whereNotNull('hired_at')
            ->whereNotNull('applied_at')
            ->get(['applied_at', 'hired_at']);
        if ($apps->isEmpty()) {
            return 0.0;
        }
        $sum = 0;
        foreach ($apps as $app) {
            $sum += Carbon::parse($app->applied_at)->startOfDay()
                ->diffInDays(Carbon::parse($app->hired_at)->startOfDay());
        }

        return round($sum / $apps->count(), 1);
    }
}
