<?php

namespace App\Domain\Subscription;

use App\Models\Subscription;
use App\Models\SubscriptionPayment;
use App\Enums\PaymentProofStatus;
use Carbon\CarbonImmutable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

/**
 * Platform metrics for the super-admin dashboard. All queries bypass the
 * tenant scope (platform-wide) and exclude demo subscriptions.
 */
class MetricsService
{
    protected function base()
    {
        return Subscription::query()->withoutGlobalScope('tenant')->where('is_demo', false);
    }

    /** Current MRR (sum of normalized monthly IQD for active subs). */
    public function mrr(): int
    {
        return (int) $this->base()->where('status', 'active')->sum('mrr_iqd');
    }

    /** Annual run-rate. */
    public function arr(): int
    {
        return $this->mrr() * 12;
    }

    public function counts(): array
    {
        $b = fn () => $this->base();

        return [
            'trialing' => $b()->where('status', 'trialing')->count(),
            'active' => $b()->where('status', 'active')->count(),
            'grace' => $b()->where('status', 'grace')->count(),
            'suspended' => $b()->where('status', 'suspended')->count(),
            'cancelled' => $b()->where('status', 'cancelled')->count(),
            'paying' => $b()->where('status', 'active')->count(),
        ];
    }

    /**
     * Monthly churn rate = cancellations this month / active-at-month-start.
     * Active-at-start is approximated as active + cancelled-this-month.
     */
    public function churnRate(): float
    {
        $start = CarbonImmutable::now()->startOfMonth();
        $cancelledThisMonth = $this->base()
            ->where('status', 'cancelled')
            ->where('cancelled_at', '>=', $start)->count();

        $activeNow = $this->base()->where('status', 'active')->count();
        $denominator = $activeNow + $cancelledThisMonth;

        return $denominator > 0 ? round($cancelledThisMonth / $denominator * 100, 1) : 0.0;
    }

    /** Trial → paid conversion rate (all-time). */
    public function trialConversionRate(): float
    {
        $everPaid = $this->base()->whereNotNull('cancelled_at')->count()
            + $this->base()->where('status', 'active')->count();
        $total = $this->base()->count();

        return $total > 0 ? round($this->base()->where('status', 'active')->count() / max(1, $total) * 100, 1) : 0.0;
    }

    /** Collected platform revenue (approved payments) over N months, by month. */
    public function revenueByMonth(int $months = 6): Collection
    {
        $start = CarbonImmutable::now()->subMonths($months - 1)->startOfMonth();

        $rows = SubscriptionPayment::query()->withoutGlobalScope('tenant')
            ->where('status', PaymentProofStatus::Approved->value)
            ->where('created_at', '>=', $start)
            ->get(['amount', 'currency', 'created_at']);

        return collect(range($months - 1, 0))->map(function ($ago) use ($rows) {
            $month = CarbonImmutable::now()->subMonths($ago);
            $inMonth = $rows->filter(fn ($p) => $p->created_at->isSameMonth($month));

            // Normalize USD→IQD for display roll-up (approx; configurable later).
            $iqd = $inMonth->sum(fn ($p) => $p->currency === 'USD'
                ? (int) round($p->amount / 100 * 1320) // cents→USD→IQD
                : $p->amount);

            return ['label' => $month->format('M Y'), 'total' => (int) $iqd];
        });
    }

    public function mrrByGateway(): Collection
    {
        return $this->base()->where('status', 'active')
            ->select('gateway', DB::raw('SUM(mrr_iqd) as total'), DB::raw('COUNT(*) as count'))
            ->groupBy('gateway')->get();
    }

    /** Clinics whose paid/trial period ends within N days (action list). */
    public function expiringClinics(int $days = 7): Collection
    {
        return $this->base()
            ->whereIn('status', ['trialing', 'active'])
            ->whereNotNull('current_period_ends_at')
            ->where('current_period_ends_at', '>', CarbonImmutable::now())
            ->where('current_period_ends_at', '<=', CarbonImmutable::now()->addDays($days))
            ->with('tenant:id,name,slug')
            ->orderBy('current_period_ends_at')->get();
    }

    public function expiringCount(int $days = 7): int
    {
        return $this->base()
            ->whereIn('status', ['trialing', 'active'])
            ->where('current_period_ends_at', '>', CarbonImmutable::now())
            ->where('current_period_ends_at', '<=', CarbonImmutable::now()->addDays($days))
            ->count();
    }

    /** Approved platform revenue grouped by payment method (all-time or window). */
    public function revenueByMethod(?int $days = null): Collection
    {
        $q = SubscriptionPayment::query()->withoutGlobalScope('tenant')
            ->where('status', PaymentProofStatus::Approved->value);
        if ($days) {
            $q->where('created_at', '>=', CarbonImmutable::now()->subDays($days));
        }

        return $q->get(['gateway', 'amount', 'currency'])
            ->groupBy('gateway')
            ->map(fn ($rows, $gateway) => [
                'gateway' => $gateway,
                'count' => $rows->count(),
                'total_iqd' => (int) $rows->sum(fn ($p) => $p->currency === 'USD'
                    ? (int) round($p->amount / 100 * 1320)
                    : $p->amount),
            ])->values();
    }

    /**
     * Trial funnel counts: started (all non-demo subs ever), converted
     * (tenants with a conversion timestamp), expired (suspended/cancelled
     * that never converted).
     */
    public function trialFunnel(): array
    {
        $started = $this->base()->count();
        $converted = \App\Models\Tenant::withoutGlobalScope('tenant')
            ->where('is_demo', false)->whereNotNull('subscription_converted_at')->count();
        $expired = $this->base()
            ->whereIn('status', ['suspended', 'cancelled'])
            ->whereHas('tenant', fn ($t) => $t->whereNull('subscription_converted_at'))
            ->count();

        return [
            'started' => $started,
            'converted' => $converted,
            'expired' => $expired,
            'rate' => $started > 0 ? round($converted / $started * 100, 1) : 0.0,
        ];
    }
}
