<?php

namespace App\Services\Reports;

use App\Models\GeneratedReport;
use App\Models\ReportSchedule;
use App\Services\Mail\ReportMailer;
use Illuminate\Database\Eloquent\Collection;
use Throwable;

class ReportScheduleRunner
{
    public function __construct(
        private readonly ReportGenerator $generator,
        private readonly ReportMailer $mailer,
        private readonly ReportPeriodResolver $periodResolver,
        private readonly ScheduleNextRunCalculator $nextRunCalculator,
        private readonly ReportTemplateDefaults $templateDefaults,
    ) {
    }

    /**
     * @return array<int, GeneratedReport>
     */
    public function runDue(bool $force = false): array
    {
        /** @var Collection<int, ReportSchedule> $schedules */
        $schedules = ReportSchedule::with(['client', 'template'])
            ->where('is_active', true)
            ->when(! $force, function ($query) {
                $query->where(function ($sub) {
                    $sub->whereNull('next_run_at')->orWhere('next_run_at', '<=', now());
                });
            })
            ->get();

        return $schedules->map(fn (ReportSchedule $schedule) => $this->runSchedule($schedule, $force))->all();
    }

    public function runSchedule(ReportSchedule $schedule, bool $force = false): GeneratedReport
    {
        $schedule->loadMissing(['client', 'template']);

        if (! $schedule->is_active && ! $force) {
            throw new \RuntimeException('Pasif rapor planı çalıştırılamaz.');
        }

        [$dateFrom, $dateTo] = $this->periodResolver->resolve($schedule);
        $channels = $this->templateDefaults->normalizeChannels($schedule->channels ?: ($schedule->template?->channels ?: []));

        $report = GeneratedReport::create([
            'client_id' => $schedule->client_id,
            'report_template_id' => $schedule->report_template_id,
            'report_schedule_id' => $schedule->id,
            'report_type' => $schedule->frequency,
            'channels' => $channels,
            'date_from' => $dateFrom->toDateString(),
            'date_to' => $dateTo->toDateString(),
            'status' => 'processing',
        ]);

        try {
            $report = $this->generator->generate($report);

            if ($report->status !== 'completed') {
                throw new \RuntimeException($report->error_message ?: 'Rapor üretimi tamamlanamadı.');
            }

            $emailLog = $this->mailer->sendReport($report, [
                'recipients' => $schedule->recipients ?: [],
                'cc' => $schedule->cc ?: [],
                'bcc' => $schedule->bcc ?: [],
                'include_pdf' => $schedule->include_pdf,
                'include_excel' => $schedule->include_excel,
                'include_csv' => $schedule->include_csv ?? false,
            ]);

            if ($emailLog->status !== 'sent') {
                throw new \RuntimeException($emailLog->error_message ?: 'Mail gönderimi başarısız oldu.');
            }

            $schedule->update([
                'last_run_at' => now(),
                'next_run_at' => $this->nextRunCalculator->calculate($schedule),
                'last_status' => 'success',
                'last_error' => null,
            ]);
        } catch (Throwable $exception) {
            report($exception);

            $schedule->update([
                'last_run_at' => now(),
                'next_run_at' => $this->nextRunCalculator->calculate($schedule),
                'last_status' => 'failed',
                'last_error' => $exception->getMessage(),
            ]);

            if ($report->exists && $report->status !== 'completed') {
                $report->update([
                    'status' => 'failed',
                    'error_message' => $exception->getMessage(),
                ]);
            }
        }

        return $report->refresh();
    }
}
