<?php

namespace App\Services;

use App\Enums\CashTransactionType;
use App\Enums\EmployeeAdvanceStatus;
use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
use App\Enums\PaymentType;
use App\Enums\PayrollStatus;
use App\Enums\RawMaterialUnit;
use App\Enums\Role;
use App\Models\Attendance;
use App\Models\CashAccount;
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\Purchase;
use App\Models\PurchaseItem;
use App\Models\RestockItem;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;

class AnalysisService
{
    public function getAttendanceStats(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $start = $startDate ? Carbon::parse($startDate) : Carbon::now()->startOfMonth();
        $end = $endDate ? Carbon::parse($endDate) : Carbon::now();

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

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

            $isWithinRange = $employee->join_date <= $end
                && (is_null($employee->resign_date) || $employee->resign_date >= $start);

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

            $present = Attendance::where('employee_id', $employee->id)
                ->whereBetween('attendance_date', [$start->toDateString(), $end->toDateString()])
                ->distinct('employee_id')
                ->count('employee_id');

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

            $workingDays = $this->countWorkingDays($start, $end);
            $absent = max(0, $workingDays - $present - $onLeave);

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

        $employees = Employee::whereHas('user', fn ($q) => $q
            ->where('is_active', true)
            ->whereHas('roles', fn ($r) => $r
                ->whereHas('permissions', fn ($p) => $p
                    ->where('name', 'attendances.create')
                )
            )
        )
            ->where('join_date', '<=', $end)
            ->where(function ($q) use ($start) {
                $q->whereNull('resign_date')->orWhere('resign_date', '>=', $start);
            })
            ->get();

        $employeeIds = $employees->pluck('id');
        $employeeCount = $employeeIds->count();

        $present = Attendance::whereIn('employee_id', $employeeIds)
            ->whereBetween('attendance_date', [$start->toDateString(), $end->toDateString()])
            ->distinct('employee_id')
            ->count('employee_id');

        $onLeave = LeaveRequest::approved()
            ->where('start_date', '<=', $end)
            ->where('end_date', '>=', $start)
            ->whereIn('employee_id', $employeeIds)
            ->count();

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

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

    public function getMyAttendance(User $user, ?string $startDate, ?string $endDate): ?array
    {
        $employee = $user->employee;

        if (! $employee) {
            return null;
        }

        $start = $startDate ? Carbon::parse($startDate) : Carbon::now()->startOfMonth();
        $end = $endDate ? Carbon::parse($endDate) : Carbon::now();

        $workingDays = 0;
        $current = $start->copy();

        while ($current->lte($end)) {
            if ($current->dayOfWeek !== Carbon::SUNDAY) {
                $workingDays++;
            }
            $current->addDay();
        }

        $present = Attendance::where('employee_id', $employee->id)
            ->whereBetween('attendance_date', [$start, $end])
            ->count();

        $leaveDays = LeaveRequest::approved()
            ->where('employee_id', $employee->id)
            ->where('start_date', '<=', $end)
            ->where('end_date', '>=', $start)
            ->get()
            ->reduce(function ($carry, $leave) use ($start, $end) {
                $leaveStart = max($leave->start_date->timestamp, $start->timestamp);
                $leaveEnd = min($leave->end_date->timestamp, $end->timestamp);
                $days = Carbon::createFromTimestamp($leaveStart)->diffInDays(Carbon::createFromTimestamp($leaveEnd)) + 1;

                return $carry + max(0, $days);
            }, 0);

        $absent = max(0, $workingDays - $present - $leaveDays);

        return [
            'total_days' => $workingDays,
            'present_days' => $present,
            'absent_days' => $absent,
            'leave_days' => $leaveDays,
            'percentage' => $workingDays > 0 ? round(($present / $workingDays) * 100) : 0,
        ];
    }

    public function getCashOverview(?string $startDate, ?string $endDate): array
    {
        $cashAccount = CashAccount::first();

        if (! $cashAccount) {
            return [
                'total_balance' => 0,
                'total_transactions' => 0,
                'total_deposit' => 0,
                'total_withdrawal' => 0,
            ];
        }

        $transactions = $cashAccount->cashTransactions();
        $this->applyDateFilter($transactions, $startDate, $endDate, 'cash_transactions.created_at');

        $totalDeposit = (clone $transactions)->where('type', CashTransactionType::DEPOSIT)->sum('amount');
        $totalWithdrawal = (clone $transactions)->where('type', CashTransactionType::WITHDRAWAL)->sum('amount');

        return [
            'total_balance' => (int) $totalDeposit - (int) $totalWithdrawal,
            'total_transactions' => (clone $transactions)->count(),
            'total_deposit' => (int) $totalDeposit,
            'total_withdrawal' => (int) $totalWithdrawal,
        ];
    }

    public function getRawMaterialStock(): array
    {
        $query = PurchaseItem::query()
            ->join('purchases', 'purchase_items.purchase_id', '=', 'purchases.id')
            ->leftJoin('raw_material_prices', 'purchase_items.raw_material_price_id', '=', 'raw_material_prices.id')
            ->leftJoin('raw_materials', 'raw_material_prices.raw_material_id', '=', 'raw_materials.id');

        $items = $query->select('purchase_items.*', 'raw_materials.unit')
            ->get();

        $totalQty = $items->sum('quantity');
        $totalValue = $items->sum('subtotal');

        $byUnit = [
            'yard' => $items->filter(fn ($i) => $i->unit === RawMaterialUnit::YARD)->sum('quantity'),
            'meter' => $items->filter(fn ($i) => $i->unit === RawMaterialUnit::METER)->sum('quantity'),
            'kilogram' => $items->filter(fn ($i) => $i->unit === RawMaterialUnit::KG)->sum('quantity'),
        ];

        return [
            'total_stock' => $totalQty,
            'total_value' => $totalValue,
            'by_unit' => $byUnit,
        ];
    }

    public function getProductStock(): array
    {
        $query = RestockItem::query()
            ->join('restocks', 'restock_items.restock_id', '=', 'restocks.id');

        $items = $query->select('restock_items.*', 'restocks.stock_type')
            ->get();

        $totalQty = $items->sum('quantity');
        $totalValue = $items->sum('subtotal');

        $byType = $items->groupBy(fn ($i) => $i->stock_type ?? 'unknown')
            ->map(fn ($group) => $group->sum('quantity'))
            ->toArray();

        return [
            'total_stock' => $totalQty,
            'total_value' => $totalValue,
            'by_type' => $byType,
        ];
    }

    public function getRevenueSummary(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $stats = (clone $query)
            ->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();

        $payrollQuery = Payroll::where('status', PayrollStatus::PAID);
        $this->applyDateFilter($payrollQuery, $startDate, $endDate, 'paid_at');
        $payrollTotal = (int) $payrollQuery->sum('total_amount');

        $expenseQuery = Expense::query();
        $this->applyDateFilter($expenseQuery, $startDate, $endDate, 'expenses.created_at');
        $expenseTotal = (int) $expenseQuery->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_deduction' => (int) $stats->total_deduction,
            'cogs' => $totalCogs,
            'gross' => $gross,
            'net' => $net,
            'payroll_total' => $payrollTotal,
            'expense_total' => $expenseTotal,
            'total_orders' => (int) $stats->total_orders,
            'avg_order' => $stats->total_orders > 0 ? (int) ($stats->total_revenue / $stats->total_orders) : 0,
        ];
    }

    public function getMonthlyRevenue(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $monthly = (clone $query)
            ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
            ->selectRaw('COALESCE(SUM(total_amount), 0) as total')
            ->selectRaw('COALESCE(SUM(discount), 0) as discount')
            ->selectRaw('COALESCE(SUM(nego_price), 0) as deduction')
            ->selectRaw('COALESCE(SUM(cogs), 0) as cogs')
            ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
            ->orderBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"))
            ->get()
            ->keyBy('month');

        $payrollMonthly = Payroll::where('status', PayrollStatus::PAID);
        $this->applyDateFilter($payrollMonthly, $startDate, $endDate, 'paid_at');

        $payrollByMonth = (clone $payrollMonthly)->toBase()
            ->selectRaw("DATE_FORMAT(paid_at, '%b %Y') as month")
            ->selectRaw('COALESCE(SUM(total_amount), 0) as payroll')
            ->groupBy(DB::raw("DATE_FORMAT(paid_at, '%Y-%m')"), DB::raw("DATE_FORMAT(paid_at, '%b %Y')"))
            ->get()
            ->keyBy('month');

        $expenseMonthly = Expense::query();
        $this->applyDateFilter($expenseMonthly, $startDate, $endDate, 'expenses.created_at');

        $expenseByMonth = (clone $expenseMonthly)->toBase()
            ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
            ->selectRaw('COALESCE(SUM(amount), 0) as expense')
            ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
            ->get()
            ->keyBy('month');

        $allMonths = [];
        foreach ([$monthly, $payrollByMonth, $expenseByMonth] as $data) {
            foreach ($data as $month => $row) {
                if (! array_key_exists($month, $allMonths)) {
                    $allMonths[$month] = $month;
                }
            }
        }

        $result = [];
        foreach ($allMonths as $month => $_) {
            $total = (int) ($monthly[$month]->total ?? 0);
            $discount = (int) ($monthly[$month]->discount ?? 0);
            $deduction = (int) ($monthly[$month]->deduction ?? 0);
            $cogs = (int) ($monthly[$month]->cogs ?? 0);
            $payroll = (int) ($payrollByMonth[$month]->payroll ?? 0);
            $expense = (int) ($expenseByMonth[$month]->expense ?? 0);
            $gross = $total - $cogs;
            $net = $gross - $payroll - $expense;

            $result[] = [
                'month' => $month,
                'total' => $total,
                'gross' => $gross,
                'net' => $net,
                'discount' => $discount,
                'deduction' => $deduction,
                'cogs' => $cogs,
                'payroll' => $payroll,
                'expense' => $expense,
            ];
        }

        return $result;
    }

    public function getMonthlyRevenueByChannel(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $monthly = (clone $query)
            ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
            ->selectRaw("COALESCE(SUM(CASE WHEN channel = 'store' THEN total_amount ELSE 0 END), 0) as store")
            ->selectRaw("COALESCE(SUM(CASE WHEN channel = 'shopee' THEN total_amount ELSE 0 END), 0) as shopee")
            ->selectRaw("COALESCE(SUM(CASE WHEN channel = 'tiktok' THEN total_amount ELSE 0 END), 0) as tiktok")
            ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
            ->orderBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"))
            ->get()
            ->map(fn ($item) => [
                'month' => $item->month,
                'store' => (int) $item->store,
                'shopee' => (int) $item->shopee,
                'tiktok' => (int) $item->tiktok,
            ]);

        return $monthly->values()->toArray();
    }

    public function getRevenueByPaymentType(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $data = (clone $query)
            ->select('payment_type')
            ->selectRaw('COALESCE(SUM(total_amount), 0) as total')
            ->groupBy('payment_type')
            ->get()
            ->map(fn ($item) => [
                'payment_type' => $item->payment_type,
                'label' => $item->payment_type->label(),
                'total' => (int) $item->total,
            ]);

        return $data->toArray();
    }

    public function getExpenseSummary(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        if ($user && $this->isMarketingUser($user)) {
            $employee = $user->employee;

            $expenseQuery = Expense::where('created_by_id', $user->id);
            $this->applyDateFilter($expenseQuery, $startDate, $endDate, 'expenses.created_at');

            $advanceQuery = EmployeeAdvance::where('status', EmployeeAdvanceStatus::REPAID);
            if ($employee) {
                $advanceQuery->where('employee_id', $employee->id);
            } else {
                $advanceQuery->whereRaw('0 = 1');
            }
            $this->applyDateFilter($advanceQuery, $startDate, $endDate, 'employee_advances.created_at');

            $expenseTotal = (clone $expenseQuery)->sum('amount');
            $advanceTotal = (clone $advanceQuery)->sum('amount');

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

        $expenseQuery = Expense::query();
        $this->applyDateFilter($expenseQuery, $startDate, $endDate, 'expenses.created_at');

        $advanceQuery = EmployeeAdvance::where('status', EmployeeAdvanceStatus::REPAID);
        $this->applyDateFilter($advanceQuery, $startDate, $endDate, 'employee_advances.created_at');

        $expenseTotal = (clone $expenseQuery)->sum('amount');
        $advanceTotal = (clone $advanceQuery)->sum('amount');

        $includePurchase = $user && $this->isPurchaseVisible($user);

        if ($includePurchase) {
            $purchaseQuery = Purchase::query();
            $this->applyDateFilter($purchaseQuery, $startDate, $endDate, 'purchases.created_at');
            $purchaseTotal = (clone $purchaseQuery)->sum('total');
        } else {
            $purchaseTotal = 0;
        }

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

    public function getMonthlyExpense(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        if ($user && $this->isMarketingUser($user)) {
            $employee = $user->employee;

            $expenseMonthly = Expense::where('created_by_id', $user->id);
            $this->applyDateFilter($expenseMonthly, $startDate, $endDate, 'expenses.created_at');

            $expenseByMonth = (clone $expenseMonthly)->toBase()
                ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
                ->selectRaw('COALESCE(SUM(amount), 0) as expense')
                ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
                ->get()
                ->keyBy('month');

            $advanceMonthly = EmployeeAdvance::where('status', EmployeeAdvanceStatus::REPAID);
            if ($employee) {
                $advanceMonthly->where('employee_id', $employee->id);
            } else {
                $advanceMonthly->whereRaw('0 = 1');
            }
            $this->applyDateFilter($advanceMonthly, $startDate, $endDate, 'employee_advances.created_at');

            $advanceByMonth = (clone $advanceMonthly)->toBase()
                ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
                ->selectRaw('COALESCE(SUM(amount), 0) as advance')
                ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
                ->get()
                ->keyBy('month');

            $allMonths = [];
            foreach ([$expenseByMonth, $advanceByMonth] as $data) {
                foreach ($data as $month => $row) {
                    if (! array_key_exists($month, $allMonths)) {
                        $allMonths[$month] = ['month' => $month, 'total' => 0, 'purchase' => 0, 'expense' => 0, 'advance' => 0];
                    }
                }
            }

            foreach ($allMonths as $month => &$row) {
                $row['expense'] = (int) ($expenseByMonth[$month]->expense ?? 0);
                $row['advance'] = (int) ($advanceByMonth[$month]->advance ?? 0);
                $row['total'] = $row['expense'] + $row['advance'];
            }

            return array_values($allMonths);
        }

        $expenseMonthly = Expense::query();
        $this->applyDateFilter($expenseMonthly, $startDate, $endDate, 'expenses.created_at');

        $expenseByMonth = (clone $expenseMonthly)->toBase()
            ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
            ->selectRaw('COALESCE(SUM(amount), 0) as expense')
            ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
            ->get()
            ->keyBy('month');

        $advanceMonthly = EmployeeAdvance::where('status', EmployeeAdvanceStatus::REPAID);
        $this->applyDateFilter($advanceMonthly, $startDate, $endDate, 'employee_advances.created_at');

        $advanceByMonth = (clone $advanceMonthly)->toBase()
            ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
            ->selectRaw('COALESCE(SUM(amount), 0) as advance')
            ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
            ->get()
            ->keyBy('month');

        $includePurchase = $user && $this->isPurchaseVisible($user);

        if ($includePurchase) {
            $purchaseMonthly = Purchase::query();
            $this->applyDateFilter($purchaseMonthly, $startDate, $endDate, 'purchases.created_at');

            $purchaseByMonth = (clone $purchaseMonthly)->toBase()
                ->selectRaw("DATE_FORMAT(created_at, '%b %Y') as month")
                ->selectRaw('COALESCE(SUM(total), 0) as purchase')
                ->groupBy(DB::raw("DATE_FORMAT(created_at, '%Y-%m')"), DB::raw("DATE_FORMAT(created_at, '%b %Y')"))
                ->get()
                ->keyBy('month');
        } else {
            $purchaseByMonth = collect();
        }

        $allMonths = [];
        foreach ([$expenseByMonth, $purchaseByMonth, $advanceByMonth] as $data) {
            foreach ($data as $month => $row) {
                if (! array_key_exists($month, $allMonths)) {
                    $allMonths[$month] = ['month' => $month, 'total' => 0, 'purchase' => 0, 'expense' => 0, 'advance' => 0];
                }
            }
        }

        foreach ($allMonths as $month => &$row) {
            $row['purchase'] = (int) ($purchaseByMonth[$month]->purchase ?? 0);
            $row['expense'] = (int) ($expenseByMonth[$month]->expense ?? 0);
            $row['advance'] = (int) ($advanceByMonth[$month]->advance ?? 0);
            $row['total'] = $row['expense'] + $row['advance'] + $row['purchase'];
        }

        return array_values($allMonths);
    }

    public function getBusyHours(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $hours = range(0, 23);
        $hourCounts = (clone $query)
            ->selectRaw('HOUR(created_at) as hour')
            ->selectRaw('COUNT(*) as orders')
            ->groupBy(DB::raw('HOUR(created_at)'))
            ->pluck('orders', 'hour')
            ->toArray();

        return array_map(function ($h) use ($hourCounts) {
            return [
                'hour' => sprintf('%02d:00', $h),
                'orders' => (int) ($hourCounts[$h] ?? 0),
            ];
        }, $hours);
    }

    public function getProfitMetrics(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $stats = (clone $query)
            ->selectRaw('COUNT(*) as total_orders')
            ->selectRaw('COALESCE(SUM(total_amount), 0) as total_revenue')
            ->selectRaw('COALESCE(SUM(cogs), 0) as hpp')
            ->first();

        $totalProductsSold = (clone $query)
            ->join('order_items', 'orders.id', '=', 'order_items.order_id')
            ->sum('order_items.quantity');

        $payrollQuery = Payroll::where('status', PayrollStatus::PAID);
        $this->applyDateFilter($payrollQuery, $startDate, $endDate, 'paid_at');
        $payrollTotal = (int) $payrollQuery->sum('total_amount');

        $expenseQuery = Expense::query();
        $this->applyDateFilter($expenseQuery, $startDate, $endDate, 'expenses.created_at');
        $expenseTotal = (int) $expenseQuery->sum('amount');

        $grossProfit = $stats->total_revenue - $stats->hpp;
        $netProfit = $grossProfit - $payrollTotal - $expenseTotal;
        $profitMargin = $stats->total_revenue > 0 ? round(($netProfit / $stats->total_revenue) * 100, 1) : 0;
        $aov = $stats->total_orders > 0 ? (int) ($stats->total_revenue / $stats->total_orders) : 0;
        $itemsPerTransaction = $stats->total_orders > 0 ? round($totalProductsSold / $stats->total_orders, 1) : 0;

        return [
            'total_orders' => (int) $stats->total_orders,
            'total_products_sold' => (int) $totalProductsSold,
            'hpp' => (int) $stats->hpp,
            'gross_profit' => (int) $grossProfit,
            'net_profit' => (int) $netProfit,
            'profit_margin' => $profitMargin,
            'aov' => $aov,
            'items_per_transaction' => $itemsPerTransaction,
            'payroll_total' => $payrollTotal,
            'expense_total' => $expenseTotal,
        ];
    }

    public function getTopSuppliers(?string $startDate, ?string $endDate): array
    {
        $query = Purchase::query();
        $this->applyDateFilter($query, $startDate, $endDate, 'purchases.created_at');

        return (clone $query)->toBase()
            ->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id')
            ->select('suppliers.name')
            ->selectRaw('COALESCE(SUM(purchases.total), 0) as total_amount')
            ->selectRaw('COUNT(*) as purchase_count')
            ->groupBy('suppliers.name')
            ->orderByDesc('total_amount')
            ->limit(5)
            ->get()
            ->toArray();
    }

    public function getTopCustomers(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED)->whereNotNull('orders.customer_id');
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        return (clone $query)->toBase()
            ->join('customers', 'orders.customer_id', '=', 'customers.id')
            ->select('customers.name')
            ->selectRaw('COALESCE(SUM(orders.total_amount), 0) as total_amount')
            ->selectRaw('COUNT(*) as order_count')
            ->groupBy('customers.name')
            ->orderByDesc('total_amount')
            ->limit(5)
            ->get()
            ->toArray();
    }

    public function getTopProducts(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        return (clone $query)->toBase()
            ->join('order_items', 'orders.id', '=', 'order_items.order_id')
            ->join('product_variants', 'order_items.product_variant_id', '=', 'product_variants.id')
            ->join('products', 'product_variants.product_id', '=', 'products.id')
            ->select('products.name')
            ->selectRaw('SUM(order_items.quantity) as total_qty')
            ->selectRaw('COALESCE(SUM(order_items.subtotal), 0) as total_revenue')
            ->groupBy('products.name')
            ->orderByDesc('total_qty')
            ->limit(5)
            ->get()
            ->toArray();
    }

    public function getRevenueTrend(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED);
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        return (clone $query)
            ->join('order_items', 'orders.id', '=', 'order_items.order_id')
            ->selectRaw('DATE(orders.created_at) as date')
            ->selectRaw('SUM(order_items.quantity) as qty')
            ->groupBy(DB::raw('DATE(orders.created_at)'))
            ->orderBy(DB::raw('DATE(orders.created_at)'))
            ->get()
            ->map(fn ($item) => [
                'date' => $item->date,
                'qty' => (int) $item->qty,
            ])
            ->toArray();
    }

    public function getMarketingSales(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $query = Order::where('orders.status', OrderStatus::COMPLETED)
            ->whereNotNull('orders.marketing_id');
        $this->applyDateFilter($query, $startDate, $endDate, 'orders.created_at');

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

        $orders = (clone $query)
            ->join('users', 'orders.marketing_id', '=', 'users.id')
            ->leftJoin('user_profiles', 'users.id', '=', 'user_profiles.user_id')
            ->select('orders.marketing_id', 'user_profiles.full_name as marketing_name')
            ->selectRaw('COUNT(DISTINCT orders.id) as total_orders')
            ->selectRaw('COALESCE(SUM(orders.total_amount), 0) as total_revenue')
            ->selectRaw('COALESCE(SUM(orders.subtotal), 0) as total_subtotal')
            ->selectRaw('COALESCE(SUM(orders.discount), 0) as total_discount')
            ->groupBy('orders.marketing_id', 'user_profiles.full_name')
            ->get();

        $productCounts = (clone $query)
            ->join('order_items', 'orders.id', '=', 'order_items.order_id')
            ->selectRaw('orders.marketing_id, SUM(order_items.quantity) as total_qty')
            ->groupBy('orders.marketing_id')
            ->pluck('total_qty', 'marketing_id');

        return $orders->map(function ($item) use ($productCounts) {
            $totalOrders = (int) $item->total_orders;
            $totalRevenue = (int) $item->total_revenue;

            return [
                'marketing_name' => $item->marketing_name,
                'total_orders' => $totalOrders,
                'total_products_sold' => (int) ($productCounts[$item->marketing_id] ?? 0),
                'total_revenue' => $totalRevenue,
                'total_subtotal' => (int) $item->total_subtotal,
                'total_discount' => (int) $item->total_discount,
                'avg_order' => $totalOrders > 0 ? (int) ($totalRevenue / $totalOrders) : 0,
            ];
        })->toArray();
    }

    public function getOrderStats(?string $startDate, ?string $endDate, ?User $user = null): array
    {
        $baseQuery = Order::query();
        $this->applyDateFilter($baseQuery, $startDate, $endDate, 'orders.created_at');

        if ($user && $this->isMarketingUser($user)) {
            $baseQuery->where('orders.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,
        ];
    }

    private function applyDateFilter($query, ?string $startDate, ?string $endDate, string $dateColumn = 'created_at'): void
    {
        if ($startDate) {
            $query->whereDate($dateColumn, '>=', $startDate);
        }
        if ($endDate) {
            $query->whereDate($dateColumn, '<=', $endDate);
        }
    }

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

    private function isPurchaseVisible(User $user): bool
    {
        return $user->hasAnyRole([
            Role::DEVELOPER->value,
            Role::OWNER->value,
            Role::ADMIN_BAHAN_BAKU->value,
        ]);
    }

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

        return $query;
    }

    private function countWorkingDays(Carbon $start, Carbon $end): int
    {
        $workingDays = 0;
        $current = $start->copy();

        while ($current->lte($end)) {
            if ($current->dayOfWeek !== Carbon::SUNDAY) {
                $workingDays++;
            }
            $current->addDay();
        }

        return $workingDays;
    }
}
