<?php

namespace App\Services\SuperAdmin;

use App\Enums\PaymentStatus;
use App\Enums\SubscriptionStatus;
use App\Models\ActivityLog;
use App\Models\Appointment;
use App\Models\Business;
use App\Models\Plan;
use App\Models\Setting;
use App\Models\Subscription;
use App\Models\SubscriptionPayment;
use App\Models\SupportTicket;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class PlatformAdminService
{
    public function dashboardData(): array
    {
        $totalBusinesses = Business::query()->count();
        $activeBusinesses = Business::query()->where('status', 'active')->count();
        $trialBusinesses = Business::query()->where('status', 'trial')->count();
        $expiredBusinesses = Business::query()->where('status', 'expired')->count();
        $totalRevenue = (float) SubscriptionPayment::query()->where('status', PaymentStatus::Paid->value)->sum('amount');
        $mrr = $this->monthlyRecurringRevenue();
        $totalAppointments = Appointment::query()->count();
        $totalUsers = User::query()->count();

        return [
            'kpis' => [
                ['label' => 'Total Businesses', 'value' => number_format($totalBusinesses), 'note' => $this->createdThisMonthNote(Business::query()), 'icon' => 'briefcase'],
                ['label' => 'Active Businesses', 'value' => number_format($activeBusinesses), 'note' => $totalBusinesses ? round(($activeBusinesses / $totalBusinesses) * 100).'% active rate' : 'No businesses yet', 'icon' => 'check', 'color' => 'bg-emerald-50 text-emerald-600'],
                ['label' => 'Trial Businesses', 'value' => number_format($trialBusinesses), 'note' => 'Trial tenants on platform', 'icon' => 'timer', 'color' => 'bg-amber-50 text-amber-600', 'tone' => 'warning'],
                ['label' => 'Expired Businesses', 'value' => number_format($expiredBusinesses), 'note' => 'Needs follow-up', 'icon' => 'alert-triangle', 'color' => 'bg-red-50 text-red-600', 'tone' => 'danger'],
                ['label' => 'Monthly Recurring Revenue', 'value' => $this->money($mrr), 'note' => 'Active subscriptions only', 'icon' => 'badge-dollar-sign'],
                ['label' => 'Total Revenue', 'value' => $this->money($totalRevenue), 'note' => 'Lifetime platform revenue', 'icon' => 'dollar-sign', 'color' => 'bg-emerald-50 text-emerald-600'],
                ['label' => 'Total Appointments', 'value' => number_format($totalAppointments), 'note' => 'Across all tenants', 'icon' => 'calendar-days'],
                ['label' => 'Total Users', 'value' => number_format($totalUsers), 'note' => 'Owners and staff', 'icon' => 'users'],
            ],
            'recentBusinesses' => $this->businessRows(
                Business::query()->with(['owner', 'subscription.plan'])->latest()->limit(8)->get()
            ),
            'revenueSnapshot' => [
                ['label' => 'MRR', 'value' => $this->compactMoney($mrr), 'percent' => 78],
                ['label' => 'Trials', 'value' => number_format($trialBusinesses), 'percent' => 42],
                ['label' => 'Churn risk', 'value' => number_format($expiredBusinesses), 'percent' => 18],
            ],
            'alerts' => [
                ['label' => 'Reminder queue placeholder healthy', 'variant' => 'success'],
                ['label' => SubscriptionPayment::query()->where('status', PaymentStatus::Failed->value)->count().' failed subscription payments', 'variant' => 'warning'],
                ['label' => $this->platformSetting('system', 'maintenance_mode', false) ? 'Maintenance mode on' : 'Maintenance mode off', 'variant' => 'primary'],
            ],
        ];
    }

    public function businesses(Request $request): LengthAwarePaginator
    {
        return Business::query()
            ->with(['owner', 'subscription.plan'])
            ->withSum(['subscriptionPayments as paid_revenue' => fn (Builder $query) => $query->where('status', PaymentStatus::Paid->value)], 'amount')
            ->when($request->query('q'), function (Builder $query, string $search): void {
                $query->where(function (Builder $query) use ($search): void {
                    $query->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhereHas('owner', fn (Builder $query) => $query->where('name', 'like', "%{$search}%")->orWhere('email', 'like', "%{$search}%"));
                });
            })
            ->when($request->query('status'), fn (Builder $query, string $status) => $status !== 'all' ? $query->where('status', $status) : null)
            ->when($request->query('plan_id'), fn (Builder $query, string $planId) => $planId !== 'all' ? $query->whereHas('subscription', fn (Builder $query) => $query->where('plan_id', $planId)) : null)
            ->latest()
            ->paginate(15)
            ->withQueryString();
    }

    public function businessRows(iterable $businesses): Collection
    {
        return collect($businesses)->map(fn (Business $business) => [
            'model' => $business,
            'name' => $business->name,
            'owner' => $business->owner?->name ?? 'No owner',
            'email' => $business->email ?? $business->owner?->email ?? '-',
            'plan' => $business->subscription?->plan?->name ?? 'No plan',
            'subscription' => $business->subscription?->status_label ?? 'None',
            'subscription_variant' => $business->subscription?->status_badge_variant ?? 'muted',
            'created' => $business->created_at?->format('M d, Y') ?? '-',
            'revenue' => $this->money((float) ($business->paid_revenue ?? $business->subscriptionPayments()->where('status', PaymentStatus::Paid->value)->sum('amount'))),
            'status' => Str::headline($business->status),
            'status_variant' => $this->businessStatusVariant($business->status),
        ]);
    }

    public function businessDetails(Business $business): array
    {
        $business->load(['owner', 'subscription.plan', 'subscriptions.plan', 'subscriptionPayments']);
        $usage = [
            ['label' => 'Appointments count', 'value' => number_format($business->appointments()->count())],
            ['label' => 'Staff count', 'value' => number_format($business->staffProfiles()->count()).' / '.$this->limitText($business->subscription?->plan?->max_staff)],
            ['label' => 'Services count', 'value' => number_format($business->services()->count()).' / '.$this->limitText($business->subscription?->plan?->max_services)],
            ['label' => 'Invoices count', 'value' => number_format($business->invoices()->count()).' / '.$this->limitText($business->subscription?->plan?->max_invoices_per_month)],
        ];

        return [
            'business' => $business,
            'subscriptionHistory' => $business->subscriptions()->with('plan')->latest('starts_at')->limit(10)->get(),
            'usage' => $usage,
            'paidRevenue' => $this->money((float) $business->subscriptionPayments()->where('status', PaymentStatus::Paid->value)->sum('amount')),
        ];
    }

    public function payments(Request $request): LengthAwarePaginator
    {
        return SubscriptionPayment::query()
            ->with(['business', 'plan', 'subscription'])
            ->when($request->query('q'), function (Builder $query, string $search): void {
                $query->where('transaction_id', 'like', "%{$search}%")
                    ->orWhereHas('business', fn (Builder $query) => $query->where('name', 'like', "%{$search}%"));
            })
            ->when($request->query('status'), fn (Builder $query, string $status) => $status !== 'all' ? $query->where('status', $status) : null)
            ->when($request->query('method'), fn (Builder $query, string $method) => $method !== 'all' ? $query->where('payment_method', $method) : null)
            ->latest()
            ->paginate(15)
            ->withQueryString();
    }

    public function paymentKpis(): array
    {
        $paid = SubscriptionPayment::query()->where('status', PaymentStatus::Paid->value);
        $paidMonth = (clone $paid)->whereBetween('paid_at', [now()->startOfMonth(), now()->endOfMonth()]);
        $pendingAmount = (float) SubscriptionPayment::query()->where('status', PaymentStatus::Pending->value)->sum('amount');

        return [
            ['label' => 'Total Revenue', 'value' => $this->money((float) $paid->sum('amount')), 'note' => 'Lifetime paid payments', 'icon' => 'dollar-sign'],
            ['label' => 'Paid This Month', 'value' => $this->money((float) $paidMonth->sum('amount')), 'note' => 'Current month payments', 'icon' => 'credit-card', 'color' => 'bg-emerald-50 text-emerald-600'],
            ['label' => 'Pending Payments', 'value' => $this->money($pendingAmount), 'note' => SubscriptionPayment::query()->where('status', PaymentStatus::Pending->value)->count().' payments pending', 'icon' => 'timer', 'color' => 'bg-amber-50 text-amber-600', 'tone' => 'warning'],
            ['label' => 'Failed Payments', 'value' => number_format(SubscriptionPayment::query()->where('status', PaymentStatus::Failed->value)->count()), 'note' => 'Needs follow-up', 'icon' => 'alert-triangle', 'color' => 'bg-red-50 text-red-600', 'tone' => 'danger'],
        ];
    }

    public function users(Request $request): LengthAwarePaginator
    {
        return User::query()
            ->with(['ownedBusinesses', 'businesses'])
            ->when($request->query('q'), fn (Builder $query, string $search) => $query->where('name', 'like', "%{$search}%")->orWhere('email', 'like', "%{$search}%"))
            ->when($request->query('role'), fn (Builder $query, string $role) => $role !== 'all' ? $query->where('role', $role) : null)
            ->latest()
            ->paginate(15)
            ->withQueryString();
    }

    public function tickets(Request $request): LengthAwarePaginator
    {
        return SupportTicket::query()
            ->with(['business', 'user'])
            ->when($request->query('q'), fn (Builder $query, string $search) => $query->where('ticket_number', 'like', "%{$search}%")->orWhere('subject', 'like', "%{$search}%"))
            ->when($request->query('status'), fn (Builder $query, string $status) => $status !== 'all' ? $query->where('status', $status) : null)
            ->latest('last_reply_at')
            ->latest()
            ->paginate(15)
            ->withQueryString();
    }

    public function ticketStats(): array
    {
        return [
            ['label' => 'Open tickets', 'value' => SupportTicket::query()->where('status', 'open')->count()],
            ['label' => 'Waiting on customer', 'value' => SupportTicket::query()->where('status', 'pending')->count()],
            ['label' => 'Resolved this week', 'value' => SupportTicket::query()->whereIn('status', ['resolved', 'closed'])->where('updated_at', '>=', now()->subWeek())->count()],
        ];
    }

    public function activities(Request $request): LengthAwarePaginator
    {
        return ActivityLog::query()
            ->with(['business', 'user'])
            ->when($request->query('q'), fn (Builder $query, string $search) => $query->where('event', 'like', "%{$search}%")->orWhere('description', 'like', "%{$search}%"))
            ->latest()
            ->paginate(25)
            ->withQueryString();
    }

    public function settings(string $group): array
    {
        $defaults = config("booklio_platform.{$group}", []);

        Setting::query()
            ->whereNull('business_id')
            ->where('group', "platform_{$group}")
            ->get()
            ->each(function (Setting $setting) use (&$defaults): void {
                $defaults[$setting->name] = $this->storedValue($setting);
            });

        return $defaults;
    }

    public function saveSettings(string $group, array $payload, ?User $actor = null, ?Request $request = null): void
    {
        DB::transaction(function () use ($group, $payload, $actor, $request): void {
            foreach ($payload as $name => $value) {
                $isSecret = $this->isSecret("{$group}.{$name}");

                if ($isSecret && ! filled($value)) {
                    continue;
                }

                Setting::query()->updateOrCreate(
                    ['business_id' => null, 'group' => "platform_{$group}", 'name' => $name],
                    [
                        'value' => $isSecret ? Crypt::encryptString((string) $value) : $value,
                        'is_encrypted' => $isSecret,
                    ]
                );
            }

            $this->log($actor, "platform.settings.{$group}.updated", "Updated {$group} platform settings.", null, [
                'group' => $group,
                'keys' => array_keys($payload),
            ], $request);
        });
    }

    public function suspendBusiness(Business $business, User $actor, ?Request $request = null): void
    {
        $previous = $business->status;
        $business->forceFill(['status' => 'suspended'])->save();
        $this->log($actor, 'business.suspended', "Suspended {$business->name}.", $business, ['previous_status' => $previous], $request);
    }

    public function activateBusiness(Business $business, User $actor, ?Request $request = null): void
    {
        $previous = $business->status;
        $business->forceFill(['status' => 'active'])->save();
        $this->log($actor, 'business.activated', "Activated {$business->name}.", $business, ['previous_status' => $previous], $request);
    }

    public function log(?User $actor, string $event, string $description, mixed $subject = null, array $properties = [], ?Request $request = null): ActivityLog
    {
        return ActivityLog::query()->create([
            'business_id' => $subject instanceof Business ? $subject->id : null,
            'user_id' => $actor?->id,
            'event' => $event,
            'subject_type' => $subject ? $subject::class : null,
            'subject_id' => $subject?->id,
            'description' => $description,
            'ip_address' => $request?->ip(),
            'user_agent' => $request?->userAgent(),
            'properties' => $properties,
        ]);
    }

    public function businessStatusVariant(string $status): string
    {
        return match ($status) {
            'active' => 'success',
            'trial' => 'warning',
            'suspended', 'expired' => 'danger',
            default => 'muted',
        };
    }

    public function money(float $amount, string $currency = 'USD'): string
    {
        return match ($currency) {
            'USD' => '$'.number_format($amount, 2),
            default => $currency.' '.number_format($amount, 2),
        };
    }

    private function monthlyRecurringRevenue(): float
    {
        return Subscription::query()
            ->where('status', SubscriptionStatus::Active->value)
            ->get()
            ->sum(fn (Subscription $subscription) => $subscription->billing_cycle === 'yearly'
                ? ((float) $subscription->price / 12)
                : (float) $subscription->price);
    }

    private function createdThisMonthNote(Builder $query): string
    {
        return '+'.number_format((clone $query)->where('created_at', '>=', now()->startOfMonth())->count()).' this month';
    }

    private function compactMoney(float $amount): string
    {
        return $amount >= 1000 ? '$'.number_format($amount / 1000, 1).'k' : $this->money($amount);
    }

    private function limitText(?int $limit): string
    {
        return $limit ? number_format($limit) : 'Unlimited';
    }

    private function platformSetting(string $group, string $name, mixed $default): mixed
    {
        $setting = Setting::query()
            ->whereNull('business_id')
            ->where('group', "platform_{$group}")
            ->where('name', $name)
            ->first();

        return $setting ? $this->storedValue($setting) : $default;
    }

    private function storedValue(Setting $setting): mixed
    {
        $value = $setting->value;

        if (! $setting->is_encrypted || ! filled($value)) {
            return $value;
        }

        try {
            return Crypt::decryptString((string) $value);
        } catch (DecryptException) {
            return null;
        }
    }

    private function isSecret(string $key): bool
    {
        return in_array($key, [
            'email.smtp_password',
            'whatsapp.access_token',
            'whatsapp.webhook_verify_token',
        ], true);
    }
}
