<?php

namespace App\Services\Reports;

use App\Models\Client;
use App\Models\GeneratedReport;
use App\Models\ReportTemplate;
use Carbon\Carbon;
use Throwable;

class ReportGenerator
{
    public function __construct(
        private readonly ReportDatasetBuilder $datasetBuilder,
        private readonly ReportSummaryBuilder $summaryBuilder,
        private readonly ReportFileGenerator $fileGenerator,
        private readonly ReportTemplateDefaults $templateDefaults,
    ) {
    }

    /**
     * @param array<int, string> $channels
     */
    public function createManualReport(Client $client, string $type, Carbon $dateFrom, Carbon $dateTo, array $channels, ?int $userId = null, ?int $templateId = null): GeneratedReport
    {
        $template = $templateId ? ReportTemplate::find($templateId) : null;
        $channels = $channels ?: ($template?->channels ?: []);

        $report = GeneratedReport::create([
            'client_id' => $client->id,
            'report_template_id' => $template?->id,
            'report_type' => $type,
            'channels' => $this->templateDefaults->normalizeChannels($channels),
            'date_from' => $dateFrom->toDateString(),
            'date_to' => $dateTo->toDateString(),
            'status' => 'processing',
            'generated_by' => $userId,
        ]);

        return $this->generate($report);
    }

    public function generate(GeneratedReport $report): GeneratedReport
    {
        try {
            $report->update(['status' => 'processing', 'error_message' => null]);

            $report->loadMissing(['client', 'template']);
            $client = $report->client()->firstOrFail();
            $dateFrom = Carbon::parse($report->date_from)->startOfDay();
            $dateTo = Carbon::parse($report->date_to)->startOfDay();
            $channels = $this->templateDefaults->normalizeChannels($report->channels ?: ($report->template?->channels ?: []));

            $dataset = $this->datasetBuilder->build($client, $dateFrom, $dateTo, $channels);
            $summary = $this->summaryBuilder->build($dataset);
            $files = $this->fileGenerator->generate($report, $dataset, $summary);

            $report->update([
                'status' => 'completed',
                'channels' => $channels,
                'summary' => $summary,
                'html_path' => $files['html_path'],
                'pdf_path' => $files['pdf_path'],
                'excel_path' => $files['excel_path'],
                'csv_path' => $files['csv_path'],
                'generated_at' => now(),
            ]);
        } catch (Throwable $exception) {
            report($exception);

            $report->update([
                'status' => 'failed',
                'error_message' => $exception->getMessage(),
            ]);
        }

        return $report->refresh();
    }
}
