<?php

namespace App\Services\System;

use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentType;
use App\Enums\Role;
use App\Models\Attendance;
use App\Models\CashAccount;
use App\Models\CashTransaction;
use App\Models\Employee;
use App\Models\EmployeeAdvance;
use App\Models\Expense;
use App\Models\LeaveRequest;
use App\Models\Order;
use App\Models\Purchase;
use App\Models\User;
use Carbon\Carbon;

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

        if ($employee === null) {
            return null;
        }

        $attendance = Attendance::query()
            ->with('media')
            ->where('employee_id', $employee->id)
            ->whereDate('attendance_date', today())
            ->first();

        return $attendance?->toArray();
    }

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

        if ($employee === null) {
            return false;
        }

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

    public function canCheckInForUser(User $user): bool
    {
        return $user->can('attendances.create') && $user->employee !== null;
    }

    public function getAttendance(): array
    {
        $totalEmployees = Employee::query()->count();
        $today = Carbon::today();

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

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

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

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

    public function getCashOverview(): array
    {
        $totalBalance = CashAccount::query()->sum('balance');

        $summary = CashTransaction::query()
            ->whereDate('created_at', Carbon::today())
            ->selectRaw("
                COUNT(*) as total_transactions,
                COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as total_deposit,
                COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as total_withdrawal
            ")
            ->first();

        return [
            'total_balance' => (int) $totalBalance,
            'total_transactions' => (int) ($summary->total_transactions ?? 0),
            'total_deposit' => (int) ($summary->total_deposit ?? 0),
            'total_withdrawal' => (int) ($summary->total_withdrawal ?? 0),
        ];
    }

    public function getRevenueSummary(): array
    {
        $user = auth()->user();
        $isMarketing = $user?->hasAnyRole(['marketing-offline', 'marketing-online']) ?? false;
        $isCashier = $user?->hasRole('cashier') ?? false;

        $revenueSummary = Order::query()
            ->completed()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereDate('created_at', Carbon::today())
            ->selectRaw('SUM(total_amount) as total_revenue, SUM(discount) as total_discount, COUNT(*) as total_orders, AVG(total_amount) as avg_order')
            ->first();

        $totalMarketplaceFees = Order::query()
            ->completed()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereNotNull('marketplace_settings_snapshot')
            ->whereDate('created_at', Carbon::today())
            ->get()
            ->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0));

        return [
            'total_revenue' => (int) ($revenueSummary->total_revenue ?? 0),
            'total_discount' => (int) ($revenueSummary->total_discount ?? 0),
            'total_marketplace_fees' => $totalMarketplaceFees,
            'total_deduction' => (int) ($revenueSummary->total_discount ?? 0) + $totalMarketplaceFees,
            'total_orders' => (int) ($revenueSummary->total_orders ?? 0),
            'avg_order' => (int) ($revenueSummary->avg_order ?? 0),
        ];
    }

    public function getExpenseSummary(): array
    {
        $today = Carbon::today();

        $purchase = Purchase::query()
            ->whereDate('created_at', $today)
            ->selectRaw('COALESCE(SUM(total), 0) as total')
            ->first();

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

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

        $purchaseTotal = (int) ($purchase->total ?? 0);
        if (auth()->user()?->hasRole(Role::ADMIN_TOKO->value)) {
            $purchaseTotal = 0;
        }
        $expenseTotal = (int) ($expenses->total ?? 0);
        $advanceTotal = (int) ($employeeAdvance->total ?? 0);

        return [
            'total' => $purchaseTotal + $expenseTotal + $advanceTotal,
            'purchase_total' => $purchaseTotal,
            'expense_total' => $expenseTotal,
            'advance_total' => $advanceTotal,
        ];
    }

    public function getOrderStats(): array
    {
        $user = auth()->user();
        $isMarketing = $user?->hasAnyRole(['marketing-offline', 'marketing-online']) ?? false;
        $isCashier = $user?->hasRole('cashier') ?? false;

        $byChannel = Order::query()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereDate('created_at', Carbon::today())
            ->selectRaw('channel, COUNT(*) as count, SUM(total_amount) as total')
            ->groupBy('channel')
            ->get()
            ->map(fn ($item) => [
                'channel' => $item->channel instanceof OrderChannel ? $item->channel->value : $item->channel,
                'label' => $item->channel instanceof OrderChannel ? $item->channel->label() : OrderChannel::from($item->channel)->label(),
                'count' => (int) $item->count,
                'total' => (int) $item->total,
            ]);

        $byPaymentType = Order::query()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereDate('created_at', Carbon::today())
            ->selectRaw('payment_type, COUNT(*) as count, SUM(total_amount) as total')
            ->groupBy('payment_type')
            ->get()
            ->map(fn ($item) => [
                'payment_type' => $item->payment_type instanceof PaymentType ? $item->payment_type->value : $item->payment_type,
                'label' => $item->payment_type instanceof PaymentType ? $item->payment_type->label() : PaymentType::from($item->payment_type)->label(),
                'count' => (int) $item->count,
                'total' => (int) $item->total,
            ]);

        $byMarketing = Order::query()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereNotNull('marketing_id')
            ->whereDate('orders.created_at', Carbon::today())
            ->join('users', 'orders.marketing_id', '=', 'users.id')
            ->leftJoin('user_profiles', 'users.id', '=', 'user_profiles.user_id')
            ->selectRaw('COALESCE(user_profiles.full_name, users.username) as name, COUNT(*) as count, SUM(orders.total_amount) as total')
            ->groupBy('orders.marketing_id', 'users.username', 'user_profiles.full_name')
            ->orderByDesc('total')
            ->limit(5)
            ->get()
            ->map(fn ($item) => [
                'name' => $item->name,
                'count' => (int) $item->count,
                'total' => (int) $item->total,
            ]);

        $byStatus = Order::query()
            ->when($isMarketing, fn ($q) => $q->where('marketing_id', $user->id))
            ->when($isCashier, fn ($q) => $q->where('created_by_id', $user->id))
            ->whereDate('created_at', Carbon::today())
            ->selectRaw('status, COUNT(*) as count')
            ->groupBy('status')
            ->get()
            ->map(fn ($item) => [
                'status' => $item->status instanceof OrderStatus ? $item->status->value : $item->status,
                'label' => $item->status instanceof OrderStatus ? $item->status->label() : OrderStatus::from($item->status)->label(),
                'count' => (int) $item->count,
            ]);

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