<?php

namespace App\Modules\Dashboard\Services;

use App\Models\User;
use App\Modules\Admin\Tenancy\Models\Module;
use App\Modules\Admin\Tenancy\Models\Subscription;
use App\Modules\Admin\Tenancy\Services\ModuleAccessService;
use App\Modules\Admin\Tenancy\Services\SubscriptionService;
use App\Modules\Dashboard\DTOs\ActionCenterWidgetData;
use App\Modules\Dashboard\DTOs\DashboardViewData;
use App\Modules\Dashboard\DTOs\OperationalAlertItem;
use App\Modules\Dashboard\Repositories\DashboardModuleRepository;
use App\Modules\Dashboard\Repositories\DashboardStatsRepository;
use App\Modules\Dashboard\Repositories\OperationalMetricsRepository;
use App\Modules\Dashboard\Repositories\TenantBillingSignalsRepository;
use Illuminate\Database\Eloquent\Collection;

class DashboardService
{
    public function __construct(
        private readonly ModuleAccessService $moduleAccess,
        private readonly SubscriptionService $subscriptions,
        private readonly DashboardModuleRepository $modules,
        private readonly DashboardStatsRepository $stats,
        private readonly DashboardModuleCardBuilder $moduleCards,
        private readonly DashboardStatLabeler $statLabeler,
        private readonly OperationalMetricsRepository $operationalMetrics,
        private readonly DashboardActionCenterService $actionCenter,
        private readonly OperationalAttentionService $attention,
        private readonly TenantBillingSignalsRepository $billingSignals,
    ) {}

    public function buildViewData(User $user): DashboardViewData
    {
        $subscription = $this->activeSubscription($user);
        $planName = $subscription?->plan?->name ?? $user->tenant?->plan?->name;
        $isTrial = $subscription?->status === Subscription::STATUS_TRIAL;
        $trialDays = $this->trialDaysLeft($subscription, $isTrial);
        $statusKey = 'dashboard.subscription_status.'.($subscription?->status ?? 'none');
        $activeModules = $this->modules->allActiveOrdered();
        $enabledSlugs = $this->enabledSlugs($user, $activeModules);
        $moduleRows = $this->moduleCards->build($enabledSlugs, $activeModules);
        $statMetrics = $user->tenant !== null
            ? $this->stats->statMetricsFor($user->tenant, $enabledSlugs, $user)
            : [];
        $statCards = $this->statLabeler->label($statMetrics);
        [$widgets, $alerts] = $this->operationalPanels($user, $enabledSlugs);

        return new DashboardViewData(
            planName: $planName,
            subscriptionStatusKey: $statusKey,
            trialDaysLeft: $trialDays,
            isTrial: (bool) $isTrial,
            modules: $moduleRows,
            statCards: $statCards,
            actionWidgets: $widgets,
            attentionAlerts: $alerts,
        );
    }

    /**
     * @param  list<string>  $enabledSlugs
     * @return array{0: list<ActionCenterWidgetData>, 1: list<OperationalAlertItem>}
     */
    private function operationalPanels(User $user, array $enabledSlugs): array
    {
        if ($user->tenant === null || $user->isAdmin()) {
            return [[], []];
        }
        $tid = (int) $user->tenant_id;
        $snapshot = in_array('hr', $enabledSlugs, true)
            ? $this->operationalMetrics->snapshot($tid)
            : null;
        $widgets = $this->actionCenter->widgets($user, $snapshot, $enabledSlugs);
        $billing = $this->billingSignals->subscriptionIssueCount($user->tenant);
        $plan = $this->billingSignals->planLimitRiskCount($user->tenant);
        $alerts = $this->attention->prioritizedAlerts($user, $snapshot, $enabledSlugs, $billing, $plan);

        return [$widgets, $alerts];
    }

    private function activeSubscription(User $user): ?Subscription
    {
        if ($user->isAdmin()) {
            return null;
        }
        if ($user->tenant === null) {
            return null;
        }
        $sub = $user->tenant->activeSubscription;
        if ($sub !== null) {
            return $sub;
        }

        return $this->subscriptions->activeFor($user->tenant);
    }

    private function trialDaysLeft(?Subscription $subscription, bool $isTrial): ?int
    {
        if (! $isTrial || $subscription?->trial_ends_at === null) {
            return null;
        }
        if (! $subscription->trial_ends_at->isFuture()) {
            return 0;
        }
        $days = (int) now()->startOfDay()->diffInDays(
            $subscription->trial_ends_at->copy()->startOfDay(),
            false
        );

        return max(0, $days);
    }

    /**
     * @param  Collection<int, Module>  $activeModules
     * @return list<string>
     */
    private function enabledSlugs(User $user, Collection $activeModules): array
    {
        if ($user->isAdmin()) {
            return $activeModules->pluck('slug')->all();
        }
        $tenant = $user->tenant;
        if ($tenant === null || ! $tenant->is_active) {
            return [];
        }

        return $this->moduleAccess->activeModuleSlugsFor($tenant);
    }
}
