<?php

namespace App\Services;

use App\Models\KycDocument;
use App\Models\Mission;
use App\Models\MissionDispute;
use App\Models\MissionProof;
use App\Models\Payment;
use App\Models\Payout;
use App\Models\PushDeviceToken;
use App\Models\UserNotification;
use App\Models\User;

class BoDashboardMetrics
{
    public function summary(): array
    {
        $usersByRole = User::query()
            ->selectRaw('role, COUNT(*) as total')
            ->groupBy('role')
            ->pluck('total', 'role');

        $missionsByStatus = Mission::query()
            ->selectRaw('status, COUNT(*) as total')
            ->groupBy('status')
            ->pluck('total', 'status');

        $activeMissions = Mission::query()
            ->whereIn('status', ['accepted', 'en_route', 'arrived', 'in_queue', 'client_arrived', 'spot_transmitted'])
            ->whereNotNull('liner_id')
            ->with([
                'client:id,name',
                'liner:id,name,email,phone,is_available,current_latitude,current_longitude,current_location_updated_at',
                'latestLocationEvent',
            ])
            ->latest('updated_at')
            ->limit(100)
            ->get();

        $activeLinersById = $activeMissions
            ->mapWithKeys(function (Mission $mission): array {
                $event = $mission->latestLocationEvent;
                $liner = $mission->liner;

                if (!$liner) {
                    return [];
                }

                $latitude = $event?->latitude !== null
                    ? (float) $event->latitude
                    : ($liner->current_latitude !== null ? (float) $liner->current_latitude : null);
                $longitude = $event?->longitude !== null
                    ? (float) $event->longitude
                    : ($liner->current_longitude !== null ? (float) $liner->current_longitude : null);

                if ($latitude === null || $longitude === null) {
                    return [];
                }

                $updatedAt = $event?->created_at?->toIso8601String()
                    ?? $liner->current_location_updated_at?->toIso8601String();

                return [$liner->id => [
                    'mission_id' => $mission->id,
                    'mission_title' => $mission->title,
                    'mission_status' => $mission->status,
                    'client_name' => $mission->client?->name,
                    'latitude' => $latitude,
                    'longitude' => $longitude,
                    'updated_at' => $updatedAt,
                    'is_on_mission' => true,
                    'liner' => [
                        'id' => $liner->id,
                        'name' => $liner->name,
                        'email' => $liner->email,
                        'phone' => $liner->phone,
                        'is_available' => (bool) $liner->is_available,
                    ],
                ]];
            });

        $availableLinersWithoutMission = User::query()
            ->where('role', 'liner')
            ->where('is_available', true)
            ->whereNotNull('current_latitude')
            ->whereNotNull('current_longitude')
            ->whereNotIn('id', $activeLinersById->keys()->all())
            ->get(['id', 'name', 'email', 'phone', 'is_available', 'current_latitude', 'current_longitude', 'current_location_updated_at'])
            ->mapWithKeys(fn (User $liner): array => [
                $liner->id => [
                    'mission_id' => null,
                    'mission_title' => 'Disponible (sans mission)',
                    'mission_status' => 'available',
                    'client_name' => null,
                    'latitude' => (float) $liner->current_latitude,
                    'longitude' => (float) $liner->current_longitude,
                    'updated_at' => $liner->current_location_updated_at?->toIso8601String(),
                    'is_on_mission' => false,
                    'liner' => [
                        'id' => $liner->id,
                        'name' => $liner->name,
                        'email' => $liner->email,
                        'phone' => $liner->phone,
                        'is_available' => true,
                    ],
                ],
            ]);

        $activeLiners = $activeLinersById
            ->union($availableLinersWithoutMission)
            ->values();

        $availableLiners = User::where('role', 'liner')->where('is_available', true)->count();
        $unavailableLiners = User::where('role', 'liner')->where('is_available', false)->count();
        $activeLinersCount = $activeMissions->pluck('liner_id')->filter()->unique()->count();

        return [
            'users' => [
                'total' => User::count(),
                'clients' => (int) ($usersByRole['client'] ?? 0),
                'liners' => (int) ($usersByRole['liner'] ?? 0),
                'admins' => (int) ($usersByRole['admin'] ?? 0),
                'liners_available' => $availableLiners,
                'liners_unavailable' => $unavailableLiners,
                'liners_active' => $activeLinersCount,
            ],
            'missions' => [
                'total' => Mission::count(),
                'published' => (int) ($missionsByStatus['published'] ?? 0),
                'accepted' => (int) ($missionsByStatus['accepted'] ?? 0),
                'in_progress' => (int) (($missionsByStatus['en_route'] ?? 0) + ($missionsByStatus['arrived'] ?? 0) + ($missionsByStatus['in_queue'] ?? 0) + ($missionsByStatus['client_arrived'] ?? 0) + ($missionsByStatus['spot_transmitted'] ?? 0)),
                'completed' => (int) ($missionsByStatus['completed'] ?? 0),
                'cancelled' => (int) ($missionsByStatus['cancelled'] ?? 0),
            ],
            'finance' => [
                'payments_total' => (float) Payment::where('status', 'paid')->sum('amount'),
                'payments_pending' => (float) Payment::where('status', 'pending')->sum('amount'),
                'payouts_total' => (float) Payout::where('status', 'paid')->sum('amount'),
                'payouts_pending' => (float) Payout::where('status', 'pending')->sum('amount'),
            ],
            'kyc' => [
                'pending' => KycDocument::where('status', 'pending')->count(),
                'approved' => KycDocument::where('status', 'approved')->count(),
                'rejected' => KycDocument::where('status', 'rejected')->count(),
            ],
            'notifications' => [
                'total' => UserNotification::count(),
                'unread' => UserNotification::whereNull('read_at')->count(),
            ],
            'push' => [
                'devices_total' => PushDeviceToken::count(),
                'devices_active' => PushDeviceToken::active()->count(),
            ],
            'active_liners' => $activeLiners->all(),
            'moderation' => [
                'proofs_pending' => MissionProof::where('status', 'pending')->count(),
                'disputes_open' => MissionDispute::where('status', 'open')->count(),
            ],
            'recent' => [
                'missions' => Mission::with(['client:id,name', 'liner:id,name'])
                    ->latest()
                    ->limit(6)
                    ->get(),
                'payments' => Payment::with(['client:id,name', 'liner:id,name'])
                    ->latest()
                    ->limit(6)
                    ->get(),
                'kyc_pending' => KycDocument::with('user:id,name,email')
                    ->where('status', 'pending')
                    ->latest()
                    ->limit(8)
                    ->get(),
                'proofs_pending' => MissionProof::with(['mission:id,title,status', 'liner:id,name,email'])
                    ->where('status', 'pending')
                    ->latest()
                    ->limit(8)
                    ->get(),
                'disputes_open' => MissionDispute::with([
                    'mission:id,title,status',
                    'reporter:id,name,email',
                    'againstUser:id,name,email',
                ])
                    ->where('status', 'open')
                    ->latest()
                    ->limit(8)
                    ->get(),
            ],
        ];
    }
}
