<?php

namespace App\Services;

use App\Models\Customer;
use App\Models\Lead;
use App\Models\PipelineStage;
use App\Models\Task;
use App\Models\User;
use Carbon\Carbon;

class AnalyticsService
{
    public function dashboardMetrics(int $companyId): array
    {
        $totalLeads = Lead::withoutGlobalScope('company')->where('company_id', $companyId)->count();

        $totalCustomers = Customer::withoutGlobalScope('company')->where('company_id', $companyId)->count();

        $conversionRate = $totalLeads > 0
            ? round(($totalCustomers / $totalLeads) * 100, 1)
            : 0.0;

        $revenue = (float) Customer::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->whereNotNull('lifetime_value')
            ->sum('lifetime_value');

        $leadsPerAgent = User::query()
            ->where('company_id', $companyId)
            ->withCount(['assignedLeads'])
            ->orderByDesc('assigned_leads_count')
            ->limit(10)
            ->get()
            ->map(fn (User $u) => [
                'name' => $u->name,
                'count' => $u->assigned_leads_count,
            ])
            ->values()
            ->all();

        $leadsByMonth = Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('created_at', '>=', now()->subMonths(11)->startOfMonth())
            ->get()
            ->groupBy(fn (Lead $lead) => $lead->created_at->format('Y-m'))
            ->map(fn ($group) => $group->count())
            ->sortKeys()
            ->all();

        $openTasks = Task::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->whereNull('completed_at')
            ->count();

        $leadsLast30 = Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('created_at', '>=', now()->subDays(30))
            ->count();

        $leadsPrev30 = Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('created_at', '>=', now()->subDays(60))
            ->where('created_at', '<', now()->subDays(30))
            ->count();

        $leadsTrendPct = $leadsPrev30 > 0
            ? round((($leadsLast30 - $leadsPrev30) / $leadsPrev30) * 100, 1)
            : null;

        $tasksDueWeek = Task::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->whereNull('completed_at')
            ->whereNotNull('due_at')
            ->whereBetween('due_at', [now()->startOfDay(), now()->addDays(7)->endOfDay()])
            ->count();

        $wonStage = PipelineStage::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('name', 'Converted')
            ->first();
        $lostStage = PipelineStage::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('name', 'Lost')
            ->first();

        $wonLeads = $wonStage ? Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('pipeline_stage_id', $wonStage->id)
            ->count() : 0;

        $lostLeads = $lostStage ? Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->where('pipeline_stage_id', $lostStage->id)
            ->count() : 0;

        return [
            'total_leads' => $totalLeads,
            'total_customers' => $totalCustomers,
            'conversion_rate' => $conversionRate,
            'revenue' => $revenue,
            'leads_per_agent' => $leadsPerAgent,
            'leads_by_month' => $leadsByMonth,
            'open_tasks' => $openTasks,
            'leads_last_30_days' => $leadsLast30,
            'leads_prev_30_days' => $leadsPrev30,
            'leads_trend_pct' => $leadsTrendPct,
            'tasks_due_this_week' => $tasksDueWeek,
            'won_leads' => $wonLeads,
            'lost_leads' => $lostLeads,
        ];
    }

    public function leadsPerStage(int $companyId): array
    {
        return PipelineStage::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->orderBy('sort_order')
            ->withCount(['leads'])
            ->get()
            ->map(fn (PipelineStage $s) => [
                'name' => $s->name,
                'count' => $s->leads_count,
                'color' => $s->color,
            ])
            ->all();
    }

    /**
     * @return array{from: string, to: string, leads_in_range: int, by_source: list<array{label: string, count: int}>, by_stage: list<array{label: string, count: int}>, new_customers: int}
     */
    public function reports(int $companyId, Carbon $fromDate, Carbon $toDate): array
    {
        $leads = Lead::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->whereBetween('created_at', [$fromDate, $toDate])
            ->with('stage')
            ->get();

        $bySource = $leads->groupBy(fn (Lead $l) => $l->source ? trim($l->source) : '(no source)')
            ->map->count()
            ->sortDesc();

        $byStage = $leads->groupBy(fn (Lead $l) => $l->stage?->name ?? '(unknown)')
            ->map->count()
            ->sortDesc();

        $newCustomers = Customer::withoutGlobalScope('company')
            ->where('company_id', $companyId)
            ->whereBetween('created_at', [$fromDate, $toDate])
            ->count();

        return [
            'from' => $fromDate->toDateString(),
            'to' => $toDate->toDateString(),
            'leads_in_range' => $leads->count(),
            'by_source' => $bySource->map(fn (int $c, string $label) => ['label' => $label, 'count' => $c])->values()->all(),
            'by_stage' => $byStage->map(fn (int $c, string $label) => ['label' => $label, 'count' => $c])->values()->all(),
            'new_customers' => $newCustomers,
        ];
    }
}
