<?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\Payroll;
use App\Models\UserProfileIntro;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class DashboardController extends Controller
{
    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();

        if (! $companyId && ! ($user->is_superadmin ?? false)) {
            $stats = ['total_employees' => 0, 'present_today' => 0, 'on_leave' => 0, 'pending_leaves' => 0, 'payroll_processed' => 0, 'new_employees' => 0];
            $chartAttendance = ['labels' => [], 'data' => []];
            $chartDepartments = ['labels' => [], 'data' => []];
            $chartLeaveTypes = ['labels' => [], 'data' => []];
            $dashboardFeed = collect();
            return view('dashboard', [
                'stats' => $stats,
                'todayAttendance' => null,
                'clientIp' => $request->ip(),
                'chartAttendance' => $chartAttendance,
                'chartDepartments' => $chartDepartments,
                'chartLeaveTypes' => $chartLeaveTypes,
                'dashboardFeed' => $dashboardFeed,
            ]);
        }

        $stats = [
            'total_employees' => User::where('company_id', $companyId)->forActiveDirectory()->count(),
            'present_today' => Attendance::where('company_id', $companyId)->where('date', $today)->whereNotNull('clock_in_date_time')->distinct('user_id')->count('user_id'),
            'on_leave' => Leave::where('company_id', $companyId)->where('status', 'approved')->where('start_date', '<=', $today)->where('end_date', '>=', $today)->count(),
            'pending_leaves' => Leave::where('company_id', $companyId)->where('status', 'pending')->count(),
            'payroll_processed' => Payroll::where('company_id', $companyId)->where('status', 'paid')->count(),
            'new_employees' => User::where('company_id', $companyId)->forActiveDirectory()->whereMonth('created_at', now()->month)->count(),
        ];

        $todayAttendance = Attendance::where('company_id', $companyId)
            ->where('user_id', $user->id)
            ->where('date', $today)
            ->first();

        $chartAttendance = $this->attendanceChartData($companyId);
        $chartDepartments = $this->departmentChartData($companyId);
        $chartLeaveTypes = $this->leaveTypesChartData($companyId);
        $dashboardFeed = $this->dashboardFeed($companyId);

        return view('dashboard', [
            'stats' => $stats,
            'todayAttendance' => $todayAttendance,
            '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']);

        $onLeaveTodayCount = Leave::query()
            ->where('company_id', $companyId)
            ->where('status', 'approved')
            ->whereDate('start_date', '<=', $today)
            ->whereDate('end_date', '>=', $today)
            ->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]);
        $profileCompletion = $this->profileCompletionPercent($user, $intro);

        $dashboardFeed = $this->dashboardFeed($companyId);
        $announcements = $dashboardFeed
            ->where('type', 'announcement')
            ->take(3)
            ->values();

        $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,
            'workingRemote' => $workingRemote,
            'announcements' => $announcements,
            'intro' => $intro,
            'profileCompletion' => $profileCompletion,
            'clientIp' => $request->ip(),
            'dashboardFeed' => $dashboardFeed,
            'todayHasOpenSession' => $todayHasOpenSession,
        ]);
    }


    private function profileCompletionPercent(User $user, ?UserProfileIntro $intro): int
    {
        $signals = [
            ! empty($user->profile_photo),
            ! empty($user->phone),
            ! empty($user->dob),
            ! empty($user->joining_date),
            ! empty($user->department_id),
            ! empty($user->designation_id),
            ! empty($intro?->about),
            ! empty($intro?->job_love),
            ! empty($intro?->interests_hobbies),
            ! empty($intro?->past_experience),
        ];

        $completed = count(array_filter($signals, fn (bool $value): bool => $value));
        $total = max(1, count($signals));

        return (int) round(($completed / $total) * 100);
    }
}
