<?php

namespace App\Services;

use App\Models\ActionItem;
use App\Models\ActivityLog;
use App\Models\Blocker;
use App\Models\Meeting;
use App\Models\Project;
use App\Models\Sprint;
use App\Models\Task;
use App\Models\User;
use Carbon\Carbon;

class DashboardService
{
    public function getSummary($user = null)
    {
        $activeProjects = Project::where('status', '!=', 'done')->where('is_archived', false)->count();
        $completedProjects = Project::where('status', 'done')->count();
        $today = Carbon::today();
        $delayedProjects = Project::whereDate('end_date', '<', $today)->where('status', '!=', 'done')->where('is_archived', false)->count();

        $openTasks = Task::whereNotIn('status', ['done', 'canceled'])->count();
        $completedTasks = Task::where('status', 'done')->count();
        $delayedTasks = Task::whereDate('due_date', '<', $today)->where('status', '!=', 'done')->count();

        $teamPerformance = [];
        $workload = [];

        $riskyProjects = Project::whereIn('risk_level', ['high', 'critical'])->where('is_archived', false)->limit(5)->get();

        $upcomingDeadlines = Task::with('project')
            ->whereDate('due_date', '>=', $today)
            ->whereDate('due_date', '<=', $today->copy()->addDays(7))
            ->where('status', '!=', 'done')
            ->orderBy('due_date')
            ->limit(10)
            ->get()
            ->map(fn ($t) => [
                'id' => $t->id,
                'title' => $t->title,
                'project' => $t->project?->title,
                'due_date' => $t->due_date?->format('Y-m-d'),
                'days_left' => $today->diffInDays($t->due_date, false),
            ]);

        $recentActivities = ActivityLog::with('user')
            ->orderBy('created_at', 'desc')
            ->limit(10)
            ->get()
            ->map(fn ($log) => [
                'id' => $log->id,
                'description' => $log->description,
                'user' => $log->user?->name ?? '?',
                'created_at' => $log->created_at?->toDateTimeString(),
                'time_ago' => $log->created_at?->diffForHumans(),
            ]);

        $myTasks = collect();
        if ($user) {
            $myTasks = Task::where('assignee_id', $user->id)
                ->where('status', '!=', 'done')
                ->orderBy('due_date')
                ->limit(10)
                ->get();
        }

        $activeSprint = null;
        if ($user) {
            $sprint = Sprint::with(['project', 'tasks.assignee'])
                ->where('status', 'active')
                ->whereHas('members', fn ($query) => $query->where('users.id', $user->id))
                ->orderBy('end_date')
                ->first();

            if ($sprint) {
                $totalTasks = $sprint->tasks->count();
                $completedTasks = $sprint->tasks->where('status', 'done')->count();
                $activeSprint = [
                    'id' => $sprint->id,
                    'title' => $sprint->title,
                    'project' => $sprint->project?->title,
                    'end_date' => $sprint->end_date?->format('Y-m-d'),
                    'remaining_days' => max(Carbon::today()->diffInDays($sprint->end_date, false), 0),
                    'progress' => $totalTasks > 0 ? round(($completedTasks / $totalTasks) * 100, 2) : 0,
                    'my_tasks' => $sprint->tasks
                        ->where('assignee_id', $user->id)
                        ->values()
                        ->map(fn ($task) => [
                            'id' => $task->id,
                            'title' => $task->title,
                            'status' => $task->status,
                        ]),
                ];
            }
        }

        $todayMeetings = Meeting::whereDate('date', Carbon::today())->count();
        $teamMembers = User::count();

        $projectProgresses = Project::where('is_archived', false)
            ->select(['id', 'title', 'progress', 'status'])
            ->limit(10)
            ->get();

        return [
            'activeProjects' => $activeProjects,
            'completedProjects' => $completedProjects,
            'delayedProjects' => $delayedProjects,
            'openTasks' => $openTasks,
            'completedTasks' => $completedTasks,
            'delayedTasks' => $delayedTasks,
            'teamPerformance' => $teamPerformance,
            'workload' => $workload,
            'riskyProjects' => $riskyProjects,
            'upcomingDeadlines' => $upcomingDeadlines,
            'recentActivities' => $recentActivities,
            'myTasks' => $myTasks,
            'todayMeetings' => $todayMeetings,
            'teamMembers' => $teamMembers,
            'projectProgresses' => $projectProgresses,
            'activeSprint' => $activeSprint,
        ];
    }

    public function getChartData()
    {
        $months = collect();
        $taskCreationData = [];
        $taskCompletionData = [];

        for ($i = 5; $i >= 0; $i--) {
            $month = Carbon::now()->subMonths($i);
            $monthName = $month->format('Y-m');
            $months->push($monthName);

            $taskCreationData[] = Task::whereYear('created_at', $month->year)
                ->whereMonth('created_at', $month->month)
                ->count();

            $taskCompletionData[] = Task::where('status', 'done')
                ->whereYear('updated_at', $month->year)
                ->whereMonth('updated_at', $month->month)
                ->count();
        }

        $monthlyTasks = [];
        foreach ($months as $i => $month) {
            $monthlyTasks[] = [
                'month' => $month,
                'created' => $taskCreationData[$i],
                'completed' => $taskCompletionData[$i],
            ];
        }

        return [
            'labels' => $months->values(),
            'taskCreation' => $taskCreationData,
            'taskCompletion' => $taskCompletionData,
            'monthlyTasks' => $monthlyTasks,
            'monthly_tasks' => $monthlyTasks,
        ];
    }

    public function getMonitoring($user = null): array
    {
        $today = Carbon::today();
        $weekEnd = $today->copy()->addDays(7);

        $projects = Project::query()
            ->where('is_archived', false)
            ->withCount([
                'tasks as total_tasks_count',
                'tasks as completed_tasks_count' => fn ($query) => $query->where('status', 'done'),
                'tasks as overdue_tasks_count' => fn ($query) => $query
                    ->whereDate('due_date', '<', $today)
                    ->whereNotIn('status', ['done', 'canceled']),
                'tasks as blocked_tasks_count' => fn ($query) => $query->where('is_blocked', true),
            ])
            ->orderByRaw("CASE WHEN risk_level = 'critical' THEN 0 WHEN risk_level = 'high' THEN 1 ELSE 2 END")
            ->limit(8)
            ->get()
            ->map(function (Project $project) {
                $health = 'on_track';
                if ($project->risk_level === 'critical' || $project->overdue_tasks_count >= 5) {
                    $health = 'off_track';
                } elseif ($project->risk_level === 'high' || $project->overdue_tasks_count > 0 || $project->blocked_tasks_count > 0) {
                    $health = 'at_risk';
                }

                return [
                    'id' => $project->id,
                    'title' => $project->title,
                    'status' => $project->status,
                    'risk_level' => $project->risk_level,
                    'progress' => $project->progress,
                    'health' => $health,
                    'total_tasks' => $project->total_tasks_count,
                    'completed_tasks' => $project->completed_tasks_count,
                    'overdue_tasks' => $project->overdue_tasks_count,
                    'blocked_tasks' => $project->blocked_tasks_count,
                ];
            });

        $sprints = Sprint::with(['project:id,title'])
            ->withCount([
                'tasks as total_tasks_count',
                'tasks as completed_tasks_count' => fn ($query) => $query->where('status', 'done'),
                'tasks as blocked_tasks_count' => fn ($query) => $query->where('is_blocked', true),
            ])
            ->where('status', 'active')
            ->orderBy('end_date')
            ->limit(6)
            ->get()
            ->map(function (Sprint $sprint) use ($today) {
                $progress = $sprint->total_tasks_count > 0
                    ? round(($sprint->completed_tasks_count / $sprint->total_tasks_count) * 100)
                    : 0;
                $elapsed = max($sprint->start_date?->diffInDays($today, false) ?? 0, 0);
                $duration = max($sprint->start_date?->diffInDays($sprint->end_date) ?? 1, 1);
                $expected = min(100, round(($elapsed / $duration) * 100));
                $health = $sprint->blocked_tasks_count > 1 || $progress + 20 < $expected ? 'at_risk' : 'on_track';
                if ($sprint->end_date?->isPast() && $progress < 100) {
                    $health = 'off_track';
                }

                return [
                    'id' => $sprint->id,
                    'title' => $sprint->title,
                    'project' => $sprint->project?->title,
                    'progress' => $progress,
                    'expected_progress' => $expected,
                    'remaining_days' => max($today->diffInDays($sprint->end_date, false), 0),
                    'health' => $health,
                    'blocked_tasks' => $sprint->blocked_tasks_count,
                ];
            });

        $workload = User::query()
            ->where('status', 'active')
            ->withCount([
                'tasks as open_tasks_count' => fn ($query) => $query->whereNotIn('status', ['done', 'canceled']),
                'tasks as overdue_tasks_count' => fn ($query) => $query
                    ->whereDate('due_date', '<', $today)
                    ->whereNotIn('status', ['done', 'canceled']),
            ])
            ->orderByDesc('open_tasks_count')
            ->limit(8)
            ->get(['id', 'name'])
            ->map(fn (User $member) => [
                'id' => $member->id,
                'name' => $member->name,
                'open_tasks' => $member->open_tasks_count,
                'overdue_tasks' => $member->overdue_tasks_count,
                'load' => $member->open_tasks_count >= 10 ? 'overloaded' : ($member->open_tasks_count >= 6 ? 'high' : 'balanced'),
            ]);

        $attention = collect();
        Task::with('project:id,title')
            ->whereNotIn('status', ['done', 'canceled'])
            ->where(function ($query) use ($today, $weekEnd) {
                $query->where('is_blocked', true)
                    ->orWhereDate('due_date', '<', $today)
                    ->orWhereBetween('due_date', [$today, $weekEnd]);
            })
            ->orderBy('due_date')
            ->limit(10)
            ->get()
            ->each(fn (Task $task) => $attention->push([
                'id' => "task-{$task->id}",
                'type' => $task->is_blocked ? 'blocker' : ($task->due_date?->isPast() ? 'overdue' : 'deadline'),
                'title' => $task->title,
                'context' => $task->project?->title,
                'date' => $task->due_date?->format('Y-m-d'),
                'target_url' => "/tasks?preview={$task->id}",
            ]));

        $upcomingMeetings = Meeting::with(['project:id,title', 'sprint:id,title'])
            ->where(function ($query) use ($today) {
                $query->whereDate('date', '>', $today)
                    ->orWhere(function ($sameDay) use ($today) {
                        $sameDay->whereDate('date', $today)->whereTime('start_time', '>=', now()->format('H:i:s'));
                    });
            })
            ->whereNotIn('status', ['cancelled', 'completed'])
            ->orderBy('date')
            ->orderBy('start_time')
            ->limit(5)
            ->get()
            ->map(fn (Meeting $meeting) => [
                'id' => $meeting->id,
                'title' => $meeting->title,
                'date' => $meeting->date?->format('Y-m-d'),
                'time' => $meeting->start_time ? substr($meeting->start_time, 0, 5) : null,
                'project' => $meeting->project?->title,
                'sprint' => $meeting->sprint?->title,
                'target_url' => "/meetings/{$meeting->id}/workspace",
            ]);

        return [
            'generated_at' => now()->toIso8601String(),
            'summary' => [
                'active_projects' => Project::where('is_archived', false)->where('status', '!=', 'done')->count(),
                'projects_at_risk' => $projects->whereIn('health', ['at_risk', 'off_track'])->count(),
                'open_tasks' => Task::whereNotIn('status', ['done', 'canceled'])->count(),
                'overdue_tasks' => Task::whereDate('due_date', '<', $today)->whereNotIn('status', ['done', 'canceled'])->count(),
                'blocked_tasks' => Task::where('is_blocked', true)->whereNotIn('status', ['done', 'canceled'])->count(),
                'active_sprints' => Sprint::where('status', 'active')->count(),
                'meetings_today' => Meeting::whereDate('date', $today)->where('status', '!=', 'cancelled')->count(),
                'overdue_action_items' => ActionItem::whereDate('due_date', '<', $today)->whereNotIn('status', ['completed', 'cancelled'])->count(),
                'open_blockers' => Blocker::whereNotIn('status', ['resolved', 'closed'])->count(),
            ],
            'projects' => $projects,
            'sprints' => $sprints,
            'workload' => $workload,
            'attention' => $attention->values(),
            'upcoming_meetings' => $upcomingMeetings,
            'trends' => $this->getChartData()['monthlyTasks'],
        ];
    }
}
