<?php

declare(strict_types=1);

namespace App\Services;

class ReportService
{
    private PaymentService $payments;
    private CommissionService $commissions;
    private CourseService $courses;
    private AuthService $auth;
    private CertificateService $certificates;

    public function __construct()
    {
        $this->payments = new PaymentService();
        $this->commissions = new CommissionService();
        $this->courses = new CourseService();
        $this->auth = new AuthService();
        $this->certificates = new CertificateService();
    }

    public function overview(array $filters = []): array
    {
        $payments = $this->filteredPayments($filters);
        $approved = array_values(array_filter($payments, fn (array $payment): bool => ($payment['status'] ?? '') === 'approved'));
        $commissions = $this->commissions->all();

        return [
            'filters' => $this->normaliseFilters($filters),
            'summary' => [
                'gross_revenue' => $this->sumPayments($approved),
                'pending_revenue' => $this->sumPaymentsByStatus($payments, ['pending', 'proof_submitted']),
                'rejected_revenue' => $this->sumPaymentsByStatus($payments, ['rejected']),
                'sales_count' => count($approved),
                'payments_count' => count($payments),
                'certificates_count' => count($this->certificates->all()),
            ],
            'payment_statuses' => $this->paymentStatuses($payments),
            'course_stats' => $this->courses->stats(),
            'user_stats' => $this->auth->stats(),
            'commission_totals' => $this->commissions->totals($commissions),
            'top_courses' => $this->topCourses($approved),
            'recent_payments' => array_slice($payments, 0, 8),
            'payments' => $payments,
        ];
    }

    public function exportRows(array $filters = []): array
    {
        $report = $this->overview($filters);
        $rows = [
            ['Tipo', 'Indicador', 'Valor', 'Curso', 'Aluno', 'Estado', 'Data'],
            ['Resumo', 'Receita aprovada', (string) $report['summary']['gross_revenue'], '', '', '', date('Y-m-d')],
            ['Resumo', 'Receita pendente', (string) $report['summary']['pending_revenue'], '', '', '', date('Y-m-d')],
            ['Resumo', 'Vendas aprovadas', (string) $report['summary']['sales_count'], '', '', '', date('Y-m-d')],
            ['Resumo', 'Certificados emitidos', (string) $report['summary']['certificates_count'], '', '', '', date('Y-m-d')],
        ];

        foreach ($report['top_courses'] as $course) {
            $rows[] = [
                'Curso',
                'Top vendas',
                (string) $course['amount'],
                $course['title'],
                '',
                (string) $course['sales'],
                '',
            ];
        }

        foreach ($report['payments'] as $payment) {
            $rows[] = [
                'Pagamento',
                $payment['reference'] ?? '',
                (string) ((float) ($payment['amount'] ?? 0)),
                $payment['course_title'] ?? '',
                $payment['student_name'] ?? '',
                $payment['status'] ?? '',
                substr((string) ($payment['updated_at'] ?? $payment['created_at'] ?? ''), 0, 10),
            ];
        }

        return $rows;
    }

    private function filteredPayments(array $filters): array
    {
        $filters = $this->normaliseFilters($filters);
        $serviceFilters = [
            'status' => $filters['status'],
            'search' => $filters['search'],
        ];

        $payments = $this->payments->adminPayments($serviceFilters);

        if ($filters['date_from'] === '' && $filters['date_to'] === '') {
            return $payments;
        }

        return array_values(array_filter($payments, function (array $payment) use ($filters): bool {
            $date = substr((string) ($payment['approved_at'] ?: $payment['updated_at'] ?: $payment['created_at'] ?: ''), 0, 10);

            if ($date === '') {
                return false;
            }

            if ($filters['date_from'] !== '' && $date < $filters['date_from']) {
                return false;
            }

            if ($filters['date_to'] !== '' && $date > $filters['date_to']) {
                return false;
            }

            return true;
        }));
    }

    private function normaliseFilters(array $filters): array
    {
        $status = (string) ($filters['status'] ?? '');

        return [
            'date_from' => $this->validDate((string) ($filters['date_from'] ?? '')),
            'date_to' => $this->validDate((string) ($filters['date_to'] ?? '')),
            'status' => in_array($status, ['pending', 'proof_submitted', 'approved', 'rejected'], true) ? $status : '',
            'search' => trim((string) ($filters['search'] ?? '')),
        ];
    }

    private function validDate(string $date): string
    {
        $date = trim($date);

        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return '';
        }

        return $date;
    }

    private function sumPayments(array $payments): float
    {
        return array_sum(array_map(fn (array $payment): float => (float) ($payment['amount'] ?? 0), $payments));
    }

    private function sumPaymentsByStatus(array $payments, array $statuses): float
    {
        return $this->sumPayments(array_filter($payments, fn (array $payment): bool => in_array($payment['status'] ?? '', $statuses, true)));
    }

    private function paymentStatuses(array $payments): array
    {
        $statuses = [
            'pending' => ['count' => 0, 'amount' => 0.0],
            'proof_submitted' => ['count' => 0, 'amount' => 0.0],
            'approved' => ['count' => 0, 'amount' => 0.0],
            'rejected' => ['count' => 0, 'amount' => 0.0],
        ];

        foreach ($payments as $payment) {
            $status = $payment['status'] ?? 'pending';

            if (!isset($statuses[$status])) {
                $statuses[$status] = ['count' => 0, 'amount' => 0.0];
            }

            $statuses[$status]['count']++;
            $statuses[$status]['amount'] += (float) ($payment['amount'] ?? 0);
        }

        return $statuses;
    }

    private function topCourses(array $approvedPayments): array
    {
        $courses = [];

        foreach ($approvedPayments as $payment) {
            $courseId = (int) ($payment['course_id'] ?? 0);

            if (!isset($courses[$courseId])) {
                $courses[$courseId] = [
                    'id' => $courseId,
                    'title' => $payment['course_title'] ?? 'Curso',
                    'sales' => 0,
                    'amount' => 0.0,
                ];
            }

            $courses[$courseId]['sales']++;
            $courses[$courseId]['amount'] += (float) ($payment['amount'] ?? 0);
        }

        usort($courses, function (array $a, array $b): int {
            $amountCompare = $b['amount'] <=> $a['amount'];

            return $amountCompare !== 0 ? $amountCompare : ($b['sales'] <=> $a['sales']);
        });

        return array_slice(array_values($courses), 0, 8);
    }
}
