<?php

namespace App\Controllers\Frontend\Shopkeeper;

use App\Controllers\FrontendBaseController;
use App\Models\RewarderDiscountModel;
use App\Models\RewarderLedgerModel;
use App\Models\RewarderOrderItemModel;
use App\Models\RewarderOrderModel;
use App\Models\RewarderProductModel;
use App\Models\RewarderRewardRuleModel;
use App\Models\RewarderServiceModel;
use App\Models\RewarderWalletModel;
use App\Models\RoleModel;
use App\Models\UserModel;

class Orders extends FrontendBaseController
{
    public $title = 'Orders';
    public $menu = 'shopkeeper';
    public $submenu = 'orders';

    public function index()
    {
        if (!is_role('Shopkeeper')) {
            return redirect()->to(landing_url());
        }
        $this->permissionCheck('shop_orders_manage');

        $shopId = shopkeeper_shop_id();
        $orders = [];
        if ($shopId) {
            $orders = db_connect()->table('rewarder_orders o')
                ->select('o.*, u.name as customer_name')
                ->join('users u', 'u.id = o.customer_id', 'left')
                ->where('o.shop_id', $shopId)
                ->orderBy('o.id', 'desc')
                ->get()
                ->getResult();
        }

        return view('frontend/shopkeeper/orders/list', compact('orders', 'shopId'));
    }

    public function add()
    {
        if (!is_role('Shopkeeper')) {
            return redirect()->to(landing_url());
        }
        $this->permissionCheck('shop_orders_manage');

        $shopId = shopkeeper_shop_id();
        $customers = $this->getCustomers();
        $products = (new RewarderProductModel())->where(['shop_id' => $shopId, 'status' => 1])->orderBy('name', 'asc')->findAll();
        $services = (new RewarderServiceModel())->where(['shop_id' => $shopId, 'status' => 1])->orderBy('name', 'asc')->findAll();

        return view('frontend/shopkeeper/orders/add', compact('customers', 'products', 'services'));
    }

    public function save()
    {
        if (!is_role('Shopkeeper')) {
            return redirect()->to(landing_url());
        }
        $this->permissionCheck('shop_orders_manage');
        postAllowed();

        $shopId = shopkeeper_shop_id();
        if (!$shopId) {
            return redirect()->back()->with('notifyError', 'No shop assigned');
        }

        $customerId = (int) post('customer_id');
        $itemType = post('item_type');
        $itemId = (int) post('item_id');
        $qty = max(1, (int) post('quantity'));

        $item = null;
        if ($itemType === 'PRODUCT') {
            $item = (new RewarderProductModel())->where(['id' => $itemId, 'shop_id' => $shopId])->first();
        } elseif ($itemType === 'SERVICE') {
            $item = (new RewarderServiceModel())->where(['id' => $itemId, 'shop_id' => $shopId])->first();
        }
        if (!$item) {
            return redirect()->back()->with('notifyError', 'Invalid item');
        }

        $unitPrice = (float) $item->price;
        $subtotal = $unitPrice * $qty;
        $discountTotal = $this->calculateDiscount($shopId, $itemType, $item, $subtotal);
        $total = max(0, $subtotal - $discountTotal);
        $pointsResult = $this->calculatePoints($shopId, $itemType, $item, $qty, $total);
        $pointsEarned = (int) ($pointsResult['points'] ?? 0);
        $rewardExpireDays = (int) ($pointsResult['reward_points_expire_days'] ?? 0);

        $db = db_connect();
        $db->transStart();

        $orderId = (new RewarderOrderModel())->create([
            'shop_id' => $shopId,
            'customer_id' => $customerId,
            'subtotal' => $subtotal,
            'discount_total' => $discountTotal,
            'total' => $total,
            'points_earned' => $pointsEarned,
            'points_redeemed' => 0,
            'status' => 'COMPLETED',
            'created_by' => logged('id'),
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        (new RewarderOrderItemModel())->create([
            'order_id' => $orderId,
            'item_type' => $itemType,
            'item_id' => $itemId,
            'name' => $item->name,
            'quantity' => $qty,
            'unit_price' => $unitPrice,
            'discount_amount' => $discountTotal,
            'line_total' => $total,
            'points_earned' => $pointsEarned,
        ]);

        if ($pointsEarned > 0) {
            $ledgerCreatedAt = date('Y-m-d H:i:s');
            $expiryDate = $rewardExpireDays > 0 ? date('Y-m-d', strtotime('+' . $rewardExpireDays . ' days', strtotime($ledgerCreatedAt))) : null;
            $walletModel = new RewarderWalletModel();
            $wallet = $walletModel->where('user_id', $customerId)->first();
            if ($wallet) {
                $walletModel->update($customerId, [
                    'points_balance' => (int) $wallet->points_balance + (int) $pointsEarned,
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            } else {
                $walletModel->insert([
                    'user_id' => $customerId,
                    'points_balance' => (int) $pointsEarned,
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            }

            (new RewarderLedgerModel())->create([
                'user_id' => $customerId,
                'shop_id' => $shopId,
                'order_id' => $orderId,
                'points_delta' => (int) $pointsEarned,
                'description' => 'Points earned from order #' . $orderId,
                'status' => 1,
                'expiry_date' => $expiryDate,
                'created_at' => $ledgerCreatedAt,
            ]);
        }

        $db->transComplete();
        if ($db->transStatus() === false) {
            return redirect()->back()->with('notifyError', 'Failed to save order');
        }

        return redirect()->to('shopkeeper/orders')->with('notifySuccess', 'Order created');
    }

    public function view($id)
    {
        if (!is_role('Shopkeeper')) {
            return redirect()->to(landing_url());
        }
        $this->permissionCheck('shop_orders_manage');

        $shopId = shopkeeper_shop_id();
        $order = (new RewarderOrderModel())->where(['id' => $id, 'shop_id' => $shopId])->first();
        if (!$order) {
            return redirect()->to('shopkeeper/orders')->with('notifyError', 'Order not found');
        }
        $items = (new RewarderOrderItemModel())->where('order_id', $id)->findAll();
        $customer = (new UserModel())->getById($order->customer_id);

        return view('frontend/shopkeeper/orders/view', compact('order', 'items', 'customer'));
    }

    private function getCustomers()
    {
        $role = (new RoleModel())->where('title', 'Customer')->first();
        if (!$role) {
            return [];
        }
        return (new UserModel())->where('role', $role->id)->orderBy('name', 'asc')->findAll();
    }

    private function calculateDiscount(int $shopId, string $itemType, $item, float $subtotal): float
    {
        $now = date('Y-m-d H:i:s');
        $discounts = (new RewarderDiscountModel())
            ->where('shop_id', $shopId)
            ->where('status', 1)
            ->groupStart()
                ->where('start_at', null)->orWhere('start_at <=', $now)
            ->groupEnd()
            ->groupStart()
                ->where('end_at', null)->orWhere('end_at >=', $now)
            ->groupEnd()
            ->orderBy('id', 'desc')
            ->findAll();

        $best = 0.0;
        foreach ($discounts as $d) {
            if (!empty($d->min_amount) && $subtotal < (float) $d->min_amount) {
                continue;
            }

            $match = false;
            if ($d->applies_to === 'ALL') {
                $match = true;
            } elseif ($itemType === 'PRODUCT') {
                if ($d->applies_to === 'PRODUCT' && (int) $d->target_id === (int) $item->id) $match = true;
                if ($d->applies_to === 'PRODUCT_CATEGORY' && (int) $d->target_id === (int) ($item->category_id ?? 0)) $match = true;
            } elseif ($itemType === 'SERVICE') {
                if ($d->applies_to === 'SERVICE' && (int) $d->target_id === (int) $item->id) $match = true;
                if ($d->applies_to === 'SERVICE_CATEGORY' && (int) $d->target_id === (int) ($item->category_id ?? 0)) $match = true;
            }

            if (!$match) {
                continue;
            }

            $amount = 0.0;
            if ($d->discount_type === 'PERCENT') {
                $amount = ($subtotal * (float) $d->value) / 100.0;
            } else {
                $amount = (float) $d->value;
            }
            $amount = min($subtotal, max(0, $amount));
            if ($amount > $best) {
                $best = $amount;
            }
        }

        return $best;
    }

    private function calculatePoints(int $shopId, string $itemType, $item, int $qty, float $total): array
    {
        $rules = (new RewarderRewardRuleModel())
            ->groupStart()
                ->where('shop_id', $shopId)
                ->orWhere('shop_id', 0)
            ->groupEnd()
            ->where('status', 1)
            ->orderBy('id', 'desc')
            ->findAll();

        $best = 0;
        $bestExpireDays = 0;
        foreach ($rules as $r) {
            $minBill = isset($r->min_bill_value) ? (float) $r->min_bill_value : 0.0;
            $maxBill = isset($r->max_bill_value) ? (float) $r->max_bill_value : 0.0;
            if ($minBill > 0 && $total < $minBill) {
                continue;
            }
            if ($maxBill > 0 && $total > $maxBill) {
                continue;
            }

            $match = false;
            if ($r->applies_to === 'ALL') {
                $match = true;
            } elseif ($itemType === 'PRODUCT') {
                if ($r->applies_to === 'PRODUCT' && (int) $r->target_id === (int) $item->id) $match = true;
                if ($r->applies_to === 'PRODUCT_CATEGORY' && (int) $r->target_id === (int) ($item->category_id ?? 0)) $match = true;
            } elseif ($itemType === 'SERVICE') {
                if ($r->applies_to === 'SERVICE' && (int) $r->target_id === (int) $item->id) $match = true;
                if ($r->applies_to === 'SERVICE_CATEGORY' && (int) $r->target_id === (int) ($item->category_id ?? 0)) $match = true;
            }

            if (!$match) {
                continue;
            }

            $points = 0;
            if ($r->points_type === 'PERCENT') {
                $points = (int) round(($total * (float) $r->value) / 100.0);
            } else {
                $points = (int) round(((float) $r->value) * $qty);
            }
            if ($points > $best) {
                $best = $points;
                $bestExpireDays = isset($r->reward_points_expire_days) ? max(0, (int) $r->reward_points_expire_days) : 0;
            }
        }

        return [
            'points' => max(0, $best),
            'reward_points_expire_days' => $bestExpireDays,
        ];
    }
}

