<?php

namespace App\Http\Controllers;

use App\Models\Announcement;
use App\Models\Attendance;
use App\Models\WorkDuration;
use App\Models\Department;
use App\Models\JobPosting;
use App\Models\Leave;
use App\Models\LeaveType;
use App\Models\Holiday;
use App\Models\User;
use App\Models\UserProfileIntro;
use App\Services\Dashboard\AdminDashboardService;
use App\Services\Dashboard\SelfDashboardService;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class DashboardController extends Controller
{
    public function __construct(
        protected AdminDashboardService $adminDashboard,
        protected SelfDashboardService $selfDashboard
    ) {}

    public function __invoke(Request $request)
    {
        $user = Auth::user();
        if ($user->company_id && ! $user->isSuperAdmin() && ! $user->isTenantManager()) {
            return redirect()->route('dashboard.self');
        }
        $companyId = $user->company_id;
        $today = Carbon::today()->toDateString();

        $homeContext = $companyId
            ? $this->adminDashboard->build($user, $companyId, $today)
            : [
                'greeting' => 'Welcome',
                'zone' => 'Overview',
                'date_label' => Carbon::parse($today)->format('l, j F Y'),
                'kpis' => [],
                'secondary_stats' => [],
                'action_queue' => [],
                'quick_actions' => [],
            ];

        $chartAttendance = $this->attendanceChartData($companyId);
        $chartDepartments = $this->departmentChartData($companyId);
        $chartLeaveTypes = $this->leaveTypesChartData($companyId);
        $dashboardFeed = $this->dashboardFeed($companyId);

        return view('dashboard', [
            'homeContext' => $homeContext,
            'clientIp' => $request->ip(),
            'chartAttendance' => $chartAttendance,
            'chartDepartments' => $chartDepartments,
            'chartLeaveTypes' => $chartLeaveTypes,
            'dashboardFeed' => $dashboardFeed,
        ]);
    }

    private function dashboardFeed(?int $companyId, int $limit = 12): Collection
    {
        if (! $companyId) {
            return collect();
        }

        $announcements = Announcement::with(['creator', 'attachments'])
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->orderByDesc('is_pinned')
            ->orderByDesc('created_at')
            ->limit($limit)
            ->get()
            ->map(function (Announcement $announcement) {
                return [
                    'type' => 'announcement',
                    'title' => $announcement->title,
                    'body' => $announcement->body,
                    'author' => $announcement->creator?->name ?? 'Admin',
                    'is_pinned' => (bool) $announcement->is_pinned,
                    'status' => $announcement->is_active ? 'active' : 'inactive',
                    'created_at' => $announcement->created_at,
                    'created_at_ts' => $announcement->created_at?->timestamp ?? 0,
                    'attachments' => $announcement->attachments,
                    'index_url' => route('announcements.index'),
                ];
            });

        $jobPosts = JobPosting::with('department')
            ->where('company_id', $companyId)
            ->orderByDesc('created_at')
            ->limit($limit)
            ->get()
            ->map(function (JobPosting $jobPosting) {
                return [
                    'type' => 'job_post',
                    'title' => $jobPosting->title,
                    'body' => $jobPosting->description,
                    'author' => $jobPosting->department?->name ? ($jobPosting->department->name . ' Team') : 'Recruitment',
                    'is_pinned' => false,
                    'status' => (string) $jobPosting->status,
                    'created_at' => $jobPosting->created_at,
                    'created_at_ts' => $jobPosting->created_at?->timestamp ?? 0,
                    'location' => $jobPosting->location,
                    'employment_type' => $jobPosting->employment_type,
                    'openings' => (int) $jobPosting->openings,
                    'edit_url' => route('job-postings.edit', $jobPosting),
                    'index_url' => route('job-postings.index'),
                ];
            });

        return $announcements
            ->concat($jobPosts)
            ->sortByDesc('created_at_ts')
            ->take($limit)
            ->values();
    }

    private function attendanceChartData(?int $companyId): array
    {
        $labels = [];
        $data = [];
        for ($i = 6; $i >= 0; $i--) {
            $date = Carbon::today()->subDays($i);
            $labels[] = $date->format('D');
            $data[] = (int) Attendance::where('company_id', $companyId)
                ->where('date', $date->toDateString())
                ->whereNotNull('clock_in_date_time')
                ->selectRaw('count(distinct user_id) as c')
                ->value('c');
        }
        return ['labels' => $labels, 'data' => $data];
    }

    private function departmentChartData(?int $companyId): array
    {
        $departments = Department::where('company_id', $companyId)
            ->withCount(['users' => fn ($q) => $q->forActiveDirectory()])
            ->orderByDesc('users_count')
            ->get();
        $labels = $departments->pluck('name')->map(fn ($n) => $n ?: 'Unassigned')->all();
        $data = $departments->pluck('users_count')->all();
        if (empty($labels)) {
            $labels = ['No data'];
            $data = [0];
        }
        return ['labels' => $labels, 'data' => $data];
    }

    private function leaveTypesChartData(?int $companyId): array
    {
        $types = LeaveType::where('company_id', $companyId)
            ->withSum(['leaves as total_days' => fn ($q) => $q->where('status', 'approved')], 'total_days')
            ->orderByDesc('total_days')
            ->get();
        $labels = $types->pluck('name')->all();
        $data = $types->pluck('total_days')->map(fn ($v) => (float) $v)->all();
        if (empty($labels)) {
            $labels = ['No data'];
            $data = [0];
        }
        return ['labels' => $labels, 'data' => $data];
    }

    public function selfDashboard(Request $request)
    {
        $user = Auth::user();
        $todayDate = Carbon::today();
        $today = $todayDate->toDateString();
        $companyId = (int) ($user->company_id ?? 0);

        $todayAttendance = Attendance::where('company_id', $user->company_id)
            ->where('user_id', $user->id)
            ->where('date', $today)
            ->first();

        $myLeaves = Leave::query()
            ->where('company_id', $companyId)
            ->where('user_id', $user->id)
            ->whereIn('status', ['pending', 'approved'])
            ->orderByDesc('start_date')
            ->limit(5)
            ->get();

        $leaveTypes = LeaveType::query()
            ->where('company_id', $companyId)
            ->orderBy('name')
            ->get(['id', 'name', 'total_leaves', 'leave_count']);

        $leaveBalances = $leaveTypes->map(function (LeaveType $type) use ($companyId, $user, $todayDate) {
            $allocated = (float) ($type->leave_count ?? $type->total_leaves ?? 0);
            $used = (float) Leave::query()
                ->where('company_id', $companyId)
                ->where('user_id', $user->id)
                ->where('leave_type_id', $type->id)
                ->where('status', 'approved')
                ->whereYear('start_date', $todayDate->year)
                ->sum('total_days');

            return [
                'name' => $type->name,
                'allocated' => round($allocated, 2),
                'used' => round($used, 2),
                'remaining' => round(max(0, $allocated - $used), 2),
                'progress' => $allocated > 0 ? min(100, round(($used / $allocated) * 100, 1)) : 0,
            ];
        })->take(5)->values();

        $visibleIds = $user->visibleStaffUserIds();
        $managerVisibleIds = collect($visibleIds)
            ->filter(fn (int $id): bool => $id !== (int) $user->id)
            ->values()
            ->all();

        $pendingApprovals = empty($managerVisibleIds)
            ? 0
            : Leave::query()
                ->where('company_id', $companyId)
                ->whereIn('user_id', $managerVisibleIds)
                ->where('status', 'pending')
                ->count();

        $upcomingHolidays = Holiday::query()
            ->where('company_id', $companyId)
            ->whereDate('date', '>=', $today)
            ->orderBy('date')
            ->limit(5)
            ->get(['id', 'name', 'date']);

        $todayBirthdays = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('dob')
            ->whereRaw('DATE_FORMAT(dob, "%m-%d") = ?', [$todayDate->format('m-d')])
            ->orderByRaw('DATE_FORMAT(dob, "%m-%d")')
            ->limit(10)
            ->get(['id', 'name', 'dob', 'profile_photo']);

        $birthdays = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('dob')
            ->whereRaw('DATE_FORMAT(dob, "%m-%d") > ?', [$todayDate->format('m-d')])
            ->orderByRaw('DATE_FORMAT(dob, "%m-%d")')
            ->limit(10)
            ->get(['id', 'name', 'dob', 'profile_photo']);

        $todayAnniversaries = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('joining_date')
            ->whereRaw('DATE_FORMAT(joining_date, "%m-%d") = ?', [$todayDate->format('m-d')])
            ->orderByRaw('DATE_FORMAT(joining_date, "%m-%d")')
            ->limit(10)
            ->get(['id', 'name', 'joining_date', 'profile_photo']);

        $anniversaries = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('joining_date')
            ->whereRaw('DATE_FORMAT(joining_date, "%m-%d") > ?', [$todayDate->format('m-d')])
            ->orderByRaw('DATE_FORMAT(joining_date, "%m-%d")')
            ->limit(10)
            ->get(['id', 'name', 'joining_date', 'profile_photo']);

        $newJoinees = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('joining_date')
            ->whereYear('joining_date', $todayDate->year)
            ->whereMonth('joining_date', $todayDate->month)
            ->orderByDesc('joining_date')
            ->limit(10)
            ->get(['id', 'name', 'joining_date', 'profile_photo']);

        $onLeaveTodayPeople = Leave::query()
            ->with(['user:id,name,profile_photo'])
            ->where('company_id', $companyId)
            ->where('status', '!=', 'rejected')
            ->whereDate('start_date', '<=', $today)
            ->whereDate('end_date', '>=', $today)
            ->get()
            ->unique('user_id')
            ->values()
            ->map(fn (Leave $leave) => $leave->user)
            ->filter()
            ->sortBy(fn (User $person) => strtolower((string) $person->name))
            ->values();

        $onLeaveTodayCount = $onLeaveTodayPeople->count();

        $workingRemote = User::query()
            ->where('company_id', $companyId)
            ->forActiveDirectory()
            ->whereNotNull('work_state')
            ->whereRaw('LOWER(work_state) IN ("remote", "wfh", "work from home", "hybrid")')
            ->get(['id', 'name', 'work_state', 'profile_photo']);

        $intro = UserProfileIntro::query()->firstOrCreate(['user_id' => $user->id]);
        $selfMeta = $this->selfDashboard->buildMeta($user, $intro, $pendingApprovals);
        $profileCompletion = $selfMeta['profile_completion'];

        $dashboardFeed = $this->dashboardFeed($companyId);

        $todayHasOpenSession = false;
        if (Auth::check()) {
            $user = Auth::user();
            $today = Carbon::today()->toDateString();
            $todayAttendance = Attendance::where('company_id', $user->company_id)
                ->where('user_id', $user->id)
                ->where('date', $today)
                ->first();
            if ($todayAttendance) {
                $todayHasOpenSession = WorkDuration::query()
                    ->where('company_id', $user->company_id)
                    ->where('attendance_id', $todayAttendance->id)
                    ->whereNull('end_time')
                    ->exists();
            }
        }

        return view('dashboard-self', [
            'todayAttendance' => $todayAttendance,
            'myLeaves' => $myLeaves,
            'leaveBalances' => $leaveBalances,
            'pendingApprovals' => $pendingApprovals,
            'upcomingHolidays' => $upcomingHolidays,
            'todayBirthdays' => $todayBirthdays,
            'birthdays' => $birthdays,
            'todayAnniversaries' => $todayAnniversaries,
            'anniversaries' => $anniversaries,
            'newJoinees' => $newJoinees,
            'onLeaveTodayCount' => $onLeaveTodayCount,
            'onLeaveTodayPeople' => $onLeaveTodayPeople,
            'workingRemote' => $workingRemote,
            'intro' => $intro,
            'selfMeta' => $selfMeta,
            'profileCompletion' => $profileCompletion,
            'clientIp' => $request->ip(),
            'dashboardFeed' => $dashboardFeed,
            'todayHasOpenSession' => $todayHasOpenSession,
        ]);
    }
}
