<?php

namespace App\Services;

use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentType;
use App\Enums\PayrollStatus;
use App\Enums\Role;
use App\Models\Attendance;
use App\Models\Employee;
use App\Models\EmployeeAdvance;
use App\Models\Expense;
use App\Models\LeaveRequest;
use App\Models\Order;
use App\Models\Payroll;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;

class DashboardService
{
    public function getAttendanceStats(?User $user = null): array
    {
        $today = Carbon::now()->toDateString();

        if ($user && $this->isMarketingUser($user)) {
            $employee = $user->employee;

            if (! $employee) {
                return [
                    'total_employees' => 0,
                    'present' => 0,
                    'absent' => 0,
                    'on_leave' => 0,
                    'percentage' => 0,
                ];
            }

            $present = Attendance::where('employee_id', $employee->id)
                ->where('attendance_date', $today)
                ->count();

            $onLeave = LeaveRequest::approved()
                ->where('employee_id', $employee->id)
                ->where('start_date', '<=', $today)
                ->where('end_date', '>=', $today)
                ->count();

            $isWorking = ! in_array(Carbon::now()->dayOfWeek, [Carbon::SATURDAY, Carbon::SUNDAY]);
            $absent = $isWorking && $present === 0 && $onLeave === 0 ? 1 : 0;

            return [
                'total_employees' => 1,
                'present' => $present,
                'absent' => $absent,
                'on_leave' => $onLeave,
                'percentage' => $present > 0 ? 100 : 0,
            ];
        }

        $totalEmployees = Employee::whereHas(
            'user',
            fn ($q) => $q
                ->where('is_active', true)
                ->whereHas(
                    'roles',
                    fn ($r) => $r
                        ->whereHas(
                            'permissions',
                            fn ($p) => $p
                                ->where('name', 'attendances.create')
                        )
                )
        )->count();

        $present = Attendance::where('attendance_date', $today)
            ->whereHas(
                'employee.user',
                fn ($q) => $q
                    ->where('is_active', true)
                    ->whereHas(
                        'roles',
                        fn ($r) => $r
                            ->whereHas(
                                'permissions',
                                fn ($p) => $p
                                    ->where('name', 'attendances.create')
                            )
                    )
            )->count();

        $onLeave = LeaveRequest::approved()
            ->where('start_date', '<=', $today)
            ->where('end_date', '>=', $today)
            ->whereHas(
                'employee.user',
                fn ($q) => $q
                    ->where('is_active', true)
                    ->whereHas(
                        'roles',
                        fn ($r) => $r
                            ->whereHas(
                                'permissions',
                                fn ($p) => $p
                                    ->where('name', 'attendances.create')
                            )
                    )
            )->count();

        $absent = max(0, $totalEmployees - $present - $onLeave);

        return [
            'total_employees' => $totalEmployees,
            'present' => $present,
            'absent' => $absent,
            'on_leave' => $onLeave,
            'percentage' => $totalEmployees > 0 ? round(($present / $totalEmployees) * 100) : 0,
        ];
    }

    public function getRevenueSummary(?User $user = null): array
    {
        $today = Carbon::now()->toDateString();
        $baseQuery = Order::where('status', OrderStatus::COMPLETED)
            ->whereDate('created_at', $today);

        if ($user && $this->isMarketingUser($user)) {
            $baseQuery->where('marketing_id', $user->id);
        }

        $stats = (clone $baseQuery)
            ->selectRaw('COUNT(*) as total_orders')
            ->selectRaw('COALESCE(SUM(total_amount), 0) as total_revenue')
            ->selectRaw('COALESCE(SUM(discount), 0) as total_discount')
            ->selectRaw('COALESCE(SUM(nego_price), 0) as total_deduction')
            ->selectRaw('COALESCE(SUM(cogs), 0) as total_cogs')
            ->first();

        $payrollTotal = (int) Payroll::where('status', PayrollStatus::PAID)
            ->whereDate('paid_at', $today)
            ->sum('total_amount');

        $expenseTotal = (int) Expense::whereDate('created_at', $today)
            ->sum('amount');

        $totalRevenue = (int) $stats->total_revenue;
        $totalCogs = (int) $stats->total_cogs;
        $gross = $totalRevenue - $totalCogs;
        $net = $gross - $payrollTotal - $expenseTotal;

        return [
            'total_revenue' => $totalRevenue,
            'total_discount' => (int) $stats->total_discount,
            'total_cogs' => $totalCogs,
            'total_deduction' => (int) $stats->total_deduction,
            'gross' => $gross,
            'net' => $net,
            'payroll_total' => $payrollTotal,
            'expense_total' => $expenseTotal,
            'total_orders' => (int) $stats->total_orders,
        ];
    }

    public function getExpenseSummary(?User $user = null): array
    {
        $today = Carbon::now()->toDateString();

        if ($user && $this->isMarketingUser($user)) {
            $employee = $user->employee;

            $expenseTotal = Expense::whereDate('created_at', $today)
                ->where('created_by_id', $user->id)
                ->selectRaw('COALESCE(SUM(amount), 0) as total')
                ->first();

            $advanceQuery = EmployeeAdvance::whereDate('created_at', $today)
                ->disbursed();

            if ($employee) {
                $advanceQuery->where('employee_id', $employee->id);
            } else {
                $advanceQuery->whereRaw('0 = 1');
            }

            $advanceTotal = $advanceQuery
                ->selectRaw('COALESCE(SUM(amount), 0) as total')
                ->first();

            return [
                'total' => (int) $expenseTotal->total + (int) $advanceTotal->total,
                'expense_total' => (int) $expenseTotal->total,
                'advance_total' => (int) $advanceTotal->total,
            ];
        }

        $expenseTotal = Expense::whereDate('created_at', $today)
            ->selectRaw('COALESCE(SUM(amount), 0) as total')
            ->first();

        $advanceTotal = EmployeeAdvance::whereDate('created_at', $today)
            ->disbursed()
            ->selectRaw('COALESCE(SUM(amount), 0) as total')
            ->first();

        return [
            'total' => (int) $expenseTotal->total + (int) $advanceTotal->total,
            'expense_total' => (int) $expenseTotal->total,
            'advance_total' => (int) $advanceTotal->total,
        ];
    }

    public function getOrderStats(?User $user = null): array
    {
        $today = Carbon::now()->toDateString();
        $baseQuery = Order::whereDate('created_at', $today);

        if ($user && $this->isMarketingUser($user)) {
            $baseQuery->where('marketing_id', $user->id);
        }

        $byChannel = collect(OrderChannel::values())->map(function ($channel) use ($baseQuery) {
            $count = (clone $baseQuery)->where('channel', $channel)->count();
            $label = OrderChannel::from($channel)->label();

            return [
                'channel' => $channel,
                'label' => $label,
                'count' => $count,
                'total' => (int) (clone $baseQuery)->where('channel', $channel)->sum('total_amount'),
            ];
        });

        $byPaymentType = collect(PaymentType::values())->map(function ($paymentType) use ($baseQuery) {
            $count = (clone $baseQuery)->where('payment_type', $paymentType)->count();
            $label = PaymentType::from($paymentType)->label();

            return [
                'payment_type' => $paymentType,
                'label' => $label,
                'count' => $count,
                'total' => (int) (clone $baseQuery)->where('payment_type', $paymentType)->sum('total_amount'),
            ];
        });

        $byMarketing = (clone $baseQuery)
            ->whereNotNull('marketing_id')
            ->select('marketing_id')
            ->selectRaw('COUNT(*) as count')
            ->selectRaw('COALESCE(SUM(total_amount), 0) as total')
            ->groupBy('marketing_id')
            ->with('marketing:id')
            ->get()
            ->map(fn ($item) => [
                'name' => $item->marketing?->userProfile->full_name ?? '-',
                'count' => $item->count,
                'total' => (int) $item->total,
            ]);

        $byStatus = collect(OrderStatus::values())->map(function ($status) use ($baseQuery) {
            $count = (clone $baseQuery)->where('status', $status)->count();
            $label = OrderStatus::from($status)->label();

            return [
                'status' => $status,
                'label' => $label,
                'count' => $count,
            ];
        });

        return [
            'by_channel' => $byChannel,
            'by_payment_type' => $byPaymentType,
            'by_marketing' => $byMarketing,
            'by_status' => $byStatus,
        ];
    }

    public function getTodayAttendance(User $user): ?array
    {
        $employee = $user->employee;

        if (! $employee) {
            return null;
        }

        $attendance = Attendance::where('employee_id', $employee->id)
            ->where('attendance_date', now()->toDateString())
            ->first();

        if (! $attendance) {
            return null;
        }

        return [
            'id' => $attendance->id,
            'attendance_date' => $attendance->attendance_date,
            'check_in_at' => $attendance->check_in_at,
            'check_out_at' => $attendance->check_out_at,
            'check_in_photo' => null,
            'check_out_photo' => null,
            'check_in_latitude' => $attendance->check_in_latitude,
            'check_in_longitude' => $attendance->check_in_longitude,
            'check_out_latitude' => $attendance->check_out_latitude,
            'check_out_longitude' => $attendance->check_out_longitude,
            'work_duration_minutes' => $attendance->work_duration_minutes,
        ];
    }

    public function isOnLeave(User $user): bool
    {
        $employee = $user->employee;

        if (! $employee) {
            return false;
        }

        return LeaveRequest::approved()
            ->where('employee_id', $employee->id)
            ->where('start_date', '<=', now()->toDateString())
            ->where('end_date', '>=', now()->toDateString())
            ->exists();
    }

    private function isMarketingUser(User $user): bool
    {
        return $user->hasAnyRole([
            Role::MARKETING_OFFLINE->value,
            Role::MARKETING_ONLINE->value,
        ]);
    }

    private function applyMarketingFilter(Builder $query, User $user, string $column = 'marketing_id'): Builder
    {
        if ($this->isMarketingUser($user)) {
            $query->where($column, $user->id);
        }

        return $query;
    }
}
