<?php

namespace App\Livewire\Studio\Dashboard;

use App\Models\Bottle;
use App\Models\Expense;
use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Payment;
use App\Models\Perfume;
use App\Models\Product;
use App\Models\Purchase;
use App\Models\User;
use App\Traits\Notification\WithSubscribeNotification;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Title('Ringkasan')]
class Overview extends Component
{
    use WithSubscribeNotification;

    public array $outlets = [];

    public array $selectedOutletIds = [];

    public array $hourlyComparisonChart = [];

    public array $todayCategoryChart = [];

    public array $todayPaymentChart = [];

    public array $todayCustomerTypeChart = [];

    public array $todayTopSellingChart = [];

    public array $todayTopCustomersChart = [];

    public array $todayDiscountChart = [];

    public array $stats = [];

    public function mount(): void
    {
        $this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();

        $this->selectedOutletIds = [];
    }

    public function render(): View
    {
        $outletIds = $this->selectedOutletIds;

        $todayOrder = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->count();

        $yesterdayOrder = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->count();

        $todayIncome = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->sum('total');

        $yesterdayIncome = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->sum('total');

        $todayCogs = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->sum('cogs');

        $yesterdayCogs = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->sum('cogs');

        $todayDiscount = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->sum('discount');

        $yesterdayDiscount = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->sum('discount');

        $todayVoucher = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->whereNotNull('voucher_id')
            ->count();

        $yesterdayVoucher = Order::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->whereNotNull('voucher_id')
            ->count();

        $todayExpense = Expense::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->today()
            ->sum('amount');

        $yesterdayExpense = Expense::when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->yesterday()
            ->sum('amount');

        $todayPurchase = Purchase::query()->today()->sum('total');

        $yesterdayPurchase = Purchase::query()->yesterday()->sum('total');

        $todayGrossProfit = $todayIncome - $todayCogs - $todayDiscount;
        $yesterdayGrossProfit = $yesterdayIncome - $yesterdayCogs - $yesterdayDiscount;

        $todayNetProfit = $todayGrossProfit - $todayExpense;
        $yesterdayNetProfit = $yesterdayGrossProfit - $yesterdayExpense;

        $todaySoldPerfume = OrderItem::where('orderable_type', Perfume::class)
            ->whereHas(
                'order',
                fn ($q) => $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
            )
            ->sum('quantity');

        $yesterdaySoldPerfume = OrderItem::where('orderable_type', Perfume::class)
            ->whereHas(
                'order',
                fn ($q) => $q->yesterday()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
            )
            ->sum('quantity');

        $todayTopPerfume = OrderItem::where('orderable_type', Perfume::class)
            ->whereHas(
                'order',
                fn ($q) => $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
            )
            ->select('orderable_id', 'orderable_type', DB::raw('SUM(quantity) as total_sold'))
            ->groupBy('orderable_id', 'orderable_type')
            ->orderByDesc('total_sold')
            ->with('orderable')
            ->first();

        $yesterdayTopPerfume = OrderItem::where('orderable_type', Perfume::class)
            ->whereHas(
                'order',
                fn ($q) => $q->yesterday()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds))
            )
            ->select('orderable_id', 'orderable_type', DB::raw('SUM(quantity) as total_sold'))
            ->groupBy('orderable_id', 'orderable_type')
            ->orderByDesc('total_sold')
            ->with('orderable')
            ->first();

        // New Card: Members Joined
        $todayNewMembers = User::whereHas('customer')->whereDate('created_at', now())->count();
        $yesterdayNewMembers = User::whereHas('customer')->whereDate('created_at', now()->yesterday())->count();

        // New Card: Low Stock Alert
        $lowStockQuery = function ($query) use ($outletIds) {
            return $query->whereHas('outlets', function ($q) use ($outletIds) {
                $q->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlets.id', $outletIds))
                    ->where('stock', '<=', 10);
            });
        };
        $lowStockCount = Perfume::where($lowStockQuery)->count() +
            Product::where($lowStockQuery)->count() +
            Bottle::where($lowStockQuery)->count();

        $todayAov = $todayOrder > 0 ? $todayIncome / $todayOrder : 0;
        $yesterdayAov = $yesterdayOrder > 0 ? $yesterdayIncome / $yesterdayOrder : 0;

        $todayProfitMargin = $todayIncome > 0 ? ($todayNetProfit / $todayIncome) * 100 : 0;
        $yesterdayProfitMargin = $yesterdayIncome > 0 ? ($yesterdayNetProfit / $yesterdayIncome) * 100 : 0;

        // --- Chart Data Logic ---

        // 1. Hourly Sales Comparison (Today vs Yesterday)
        $hourFunc = DB::getDriverName() === 'sqlite' ? "CAST(strftime('%H', created_at) AS INTEGER)" : 'HOUR(created_at)';

        $todayHourly = Order::whereDate('created_at', now())
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->select(DB::raw("$hourFunc as hour"), DB::raw('count(*) as count'))
            ->groupBy('hour')
            ->get()->keyBy('hour');

        $yesterdayHourly = Order::whereDate('created_at', now()->yesterday())
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->select(DB::raw("$hourFunc as hour"), DB::raw('count(*) as count'))
            ->groupBy('hour')
            ->get()->keyBy('hour');

        $this->hourlyComparisonChart = [
            'labels' => collect(range(0, 23))->map(fn ($h) => str_pad($h, 2, '0', STR_PAD_LEFT).':00')->toArray(),
            'today' => collect(range(0, 23))->map(fn ($h) => $todayHourly->get($h)?->count ?? 0)->toArray(),
            'yesterday' => collect(range(0, 23))->map(fn ($h) => $yesterdayHourly->get($h)?->count ?? 0)->toArray(),
        ];

        // 2. Today's Distribution (Category)
        $categorySales = OrderItem::whereHas('order', function ($q) use ($outletIds) {
            $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds));
        })
            ->select('orderable_type', DB::raw('SUM(unit_price * quantity) as total'))
            ->groupBy('orderable_type')
            ->get()->keyBy('orderable_type');

        $this->todayCategoryChart = [
            'labels' => ['Parfum', 'Produk Jadi', 'Botol'],
            'data' => [
                (int) ($categorySales->get(Perfume::class)?->total ?? 0),
                (int) ($categorySales->get(Product::class)?->total ?? 0),
                (int) ($categorySales->get(Bottle::class)?->total ?? 0),
            ],
        ];

        // 3. Today's Payment Methods
        $paymentMethods = Payment::whereHas('order', function ($q) use ($outletIds) {
            $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds));
        })
            ->select('method', DB::raw('SUM(amount) as total'))
            ->groupBy('method')
            ->get();

        $this->todayPaymentChart = [
            'labels' => $paymentMethods->map(fn ($pm) => $pm->method?->label() ?? 'Unknown')->toArray(),
            'data' => $paymentMethods->pluck('total')->toArray(),
        ];

        // 4. Today's Customer Type
        $todayMemberOrders = Order::query()
            ->today()
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->whereNotNull('customer_id')->count();
        $todayGuestOrders = Order::query()
            ->today()
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->whereNull('customer_id')->count();

        $this->todayCustomerTypeChart = [
            'labels' => ['Member', 'Guest (Umum)'],
            'data' => [$todayMemberOrders, $todayGuestOrders],
        ];

        // 5. Today's Top 5 Selling Items
        $todayTopItems = OrderItem::whereHas('order', function ($q) use ($outletIds) {
            $q->today()->when(! empty($outletIds), fn ($q2) => $q2->whereIn('outlet_id', $outletIds));
        })
            ->with('orderable')
            ->select('orderable_id', 'orderable_type', DB::raw('SUM(quantity) as total_sold'))
            ->groupBy('orderable_id', 'orderable_type')
            ->orderByDesc('total_sold')
            ->take(5)
            ->get();

        $this->todayTopSellingChart = [
            'labels' => $todayTopItems->map(fn ($item) => $item->orderable?->name ?? 'Unknown')->toArray(),
            'data' => $todayTopItems->pluck('total_sold')->map(fn ($val) => (int) $val)->toArray(),
        ];

        // 6. Today's Top 5 Customers
        $todayTopCustomers = Order::query()
            ->today()
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->whereNotNull('customer_id')
            ->select('customer_id', DB::raw('SUM(total) as total_spent'))
            ->groupBy('customer_id')
            ->orderByDesc('total_spent')
            ->take(5)
            ->with('customer')
            ->get();

        $this->todayTopCustomersChart = [
            'labels' => $todayTopCustomers->map(fn ($o) => $o->customer?->user?->employee?->full_name ?? $o->customer?->user?->name ?? 'Customer #'.$o->customer_id)->toArray(),
            'data' => $todayTopCustomers->pluck('total_spent')->map(fn ($val) => (int) $val)->toArray(),
        ];

        // 7. Today's Discount Distribution (With Discount vs Regular)
        $withDiscount = Order::query()
            ->today()
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->where('discount', '>', 0)->count();
        $noDiscount = Order::query()
            ->today()
            ->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
            ->where('discount', '<=', 0)->count();

        $this->todayDiscountChart = [
            'labels' => ['Pakai Diskon', 'Harga Normal'],
            'data' => [$withDiscount, $noDiscount],
        ];

        $this->stats = array_values(array_filter([
            [
                'title' => 'Average Order Value (AOV)',
                'value' => formatCurrencyNumber($todayAov, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayAov, 'Rp'),
                'trend' => $yesterdayAov > 0
                    ? round((($todayAov - $yesterdayAov) / $yesterdayAov) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayAov > $yesterdayAov,
            ],
            [
                'title' => 'Profit Margin',
                'value' => round($todayProfitMargin, 1).'%',
                'previous' => round($yesterdayProfitMargin, 1).'%',
                'trend' => $yesterdayProfitMargin > 0
                    ? round($todayProfitMargin - $yesterdayProfitMargin, 1).'%'
                    : '∞%',
                'trendUp' => $todayProfitMargin > $yesterdayProfitMargin,
            ],
            [
                'title' => 'Total Order',
                'value' => $todayOrder,
                'previous' => $yesterdayOrder,
                'trend' => $yesterdayOrder > 0
                    ? round((($todayOrder - $yesterdayOrder) / $yesterdayOrder) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayOrder > $yesterdayOrder,
            ],
            [
                'title' => 'Pendapatan',
                'value' => formatCurrencyNumber($todayIncome, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayIncome, 'Rp'),
                'trend' => $yesterdayIncome > 0
                    ? round((($todayIncome - $yesterdayIncome) / $yesterdayIncome) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayIncome > $yesterdayIncome,
                'formatted' => formatCurrencyNumber($todayIncome, 'Rp'),
            ],

            auth()->user()->hasRole(['Developer', 'Owner']) ? [
                'title' => 'HPP',
                'value' => formatCurrencyNumber($todayCogs, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayCogs, 'Rp'),
                'trend' => $yesterdayCogs > 0
                    ? round((($todayCogs - $yesterdayCogs) / $yesterdayCogs) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayCogs > $yesterdayCogs,
                'formatted' => formatCurrencyNumber($todayCogs, 'Rp'),
            ] : null,

            [
                'title' => 'Member Baru',
                'value' => $todayNewMembers.' Orang',
                'previous' => $yesterdayNewMembers.' Orang',
                'trend' => $yesterdayNewMembers > 0
                    ? round((($todayNewMembers - $yesterdayNewMembers) / $yesterdayNewMembers) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayNewMembers > $yesterdayNewMembers,
            ],
            [
                'title' => 'Diskon',
                'value' => formatCurrencyNumber($todayDiscount, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayDiscount, 'Rp'),
                'trend' => $yesterdayDiscount > 0
                    ? round((($todayDiscount - $yesterdayDiscount) / $yesterdayDiscount) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayDiscount > $yesterdayDiscount,
                'formatted' => formatCurrencyNumber($todayDiscount, 'Rp'),
            ],
            [
                'title' => 'Voucher Terpakai',
                'value' => $todayVoucher,
                'previous' => $yesterdayVoucher,
                'trend' => $yesterdayVoucher > 0
                    ? round((($todayVoucher - $yesterdayVoucher) / $yesterdayVoucher) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayVoucher > $yesterdayVoucher,
            ],
            [
                'title' => 'Beban Toko',
                'value' => formatCurrencyNumber($todayExpense, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayExpense, 'Rp'),
                'trend' => $yesterdayExpense > 0
                    ? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayExpense > $yesterdayExpense,
            ],

            auth()->user()->hasRole(['Developer', 'Owner']) ? [
                'title' => 'Belanja Barang',
                'value' => formatCurrencyNumber($todayPurchase, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayPurchase, 'Rp'),
                'trend' => $yesterdayPurchase > 0
                    ? round((($todayPurchase - $yesterdayPurchase) / $yesterdayPurchase) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayPurchase > $yesterdayPurchase,
            ] : null,

            auth()->user()->hasRole(['Developer', 'Owner']) ? [
                'title' => 'Laba Kotor',
                'value' => formatCurrencyNumber($todayGrossProfit, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayGrossProfit, 'Rp'),
                'trend' => $yesterdayGrossProfit > 0
                    ? round((($todayGrossProfit - $yesterdayGrossProfit) / $yesterdayGrossProfit) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayGrossProfit > $yesterdayGrossProfit,
            ] : null,

            auth()->user()->hasRole(['Developer', 'Owner']) ? [
                'title' => 'Laba Bersih',
                'value' => formatCurrencyNumber($todayNetProfit, 'Rp'),
                'previous' => formatCurrencyNumber($yesterdayNetProfit, 'Rp'),
                'trend' => $yesterdayNetProfit > 0
                    ? round((($todayNetProfit - $yesterdayNetProfit) / $yesterdayNetProfit) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todayNetProfit > $yesterdayNetProfit,
            ] : null,

            [
                'title' => 'Parfum Terjual',
                'value' => $todaySoldPerfume.' ml',
                'previous' => $yesterdaySoldPerfume.' ml',
                'trend' => $yesterdaySoldPerfume > 0
                    ? round((($todaySoldPerfume - $yesterdaySoldPerfume) / $yesterdaySoldPerfume) * 100, 1).'%'
                    : '∞%',
                'trendUp' => $todaySoldPerfume > $yesterdaySoldPerfume,
            ],
            [
                'title' => 'Top Parfum',
                'value' => optional($todayTopPerfume?->orderable)->name.' ('.$todayTopPerfume?->total_sold.'ml)' ?? '-',
                'previous' => optional($yesterdayTopPerfume?->orderable)->name.'('.$yesterdayTopPerfume?->total_sold.'ml)' ?? '-',
                'trend' => ($yesterdayTopPerfume && $yesterdayTopPerfume->total_sold > 0)
                    ? round((($todayTopPerfume?->total_sold - $yesterdayTopPerfume?->total_sold) / $yesterdayTopPerfume?->total_sold) * 100, 1).'%'
                    : '∞%',
                'trendUp' => ($todayTopPerfume?->total_sold ?? 0) > ($yesterdayTopPerfume?->total_sold ?? 0),
            ],
        ]));

        return view('livewire.studio.dashboard.overview');
    }
}
