<?php

namespace App\Controllers\Api;

use App\Libraries\PhonePeService;
use App\Models\RewarderLedgerModel;
use App\Models\RewarderPaymentIntentModel;
use App\Models\RewarderPaymentModel;
use App\Models\RewarderRewardRuleModel;
use App\Models\RewarderWalletModel;
use CodeIgniter\HTTP\ResponseInterface;

class Billing extends BaseApiController
{
    public function show($shopId = null): ResponseInterface
    {
        $shopId = (int) $shopId;
        if ($shopId < 1) {
            return $this->fail('Invalid shop id.', 400);
        }

        $shop = db_connect()->table('rewarder_shops sh')
            ->select('sh.*, c.name AS city_name, cat.name AS category_name')
            ->join('rewarder_cities c', 'c.id = sh.city_id', 'left')
            ->join('rewarder_shop_categories cat', 'cat.id = sh.category_id', 'left')
            ->where('sh.id', $shopId)
            ->where('sh.status', 1)
            ->get()
            ->getRow();

        if (!$shop) {
            return $this->fail('Shop not found.', 404);
        }

        $discountId = (int) ($this->request->getGet('discount_id') ?? 0);
        $discount = $this->loadActiveDiscountForShop($shopId, $discountId);
        $rewardRules = $this->loadActiveRewardRulesForShop($shopId);

        $gateway = (string) setting('payment_gateway', 'razorpay');
        $payment = [
            'gateway' => $gateway,
        ];
        if ($gateway === '0' || $gateway === '') {
            $payment['gateway'] = 'none';
        } elseif ($gateway === 'razorpay') {
            $payment['razorpay_key'] = (string) setting('razorpay_key', '');
        } elseif ($gateway === 'phonepe') {
            $phonepeClientId = (string) setting('phonepe_client_id', '');
            $payment['phonepe_client_id'] = $phonepeClientId;
            $payment['merchant_id'] = $phonepeClientId;
            $payment['merchantId'] = $phonepeClientId;
            $payment['phonepe_client_version'] = (string) setting('phonepe_client_version', '');
        }

        return $this->ok((object) [
            'shop' => (object) [
                'id' => (int) $shop->id,
                'name' => (string) ($shop->name ?? ''),
                'slug' => (string) ($shop->slug ?? ''),
                'phone' => (string) ($shop->phone ?? ''),
                'address' => (string) ($shop->address ?? ''),
                'city_id' => (int) ($shop->city_id ?? 0),
                'city_name' => (string) ($shop->city_name ?? ''),
                'category_id' => (int) ($shop->category_id ?? 0),
                'category_name' => (string) ($shop->category_name ?? ''),
                'image_url' => !empty($shop->img_type)
                    ? urlUpload('shops/' . (int) $shop->id . '.' . $shop->img_type, false)
                    : admin_assets('img/default-150x150.png'),
            ],
            'discount' => $discount ? $this->normalizeDiscount($discount) : null,
            'reward_rules' => array_values(array_map([$this, 'normalizeRewardRule'], $rewardRules)),
            'payment' => (object) $payment,
        ]);
    }

    public function preview(): ResponseInterface
    {
        if (!$this->isLoggedIn()) {
            return $this->fail('Login required.', 401);
        }

        $data = $this->request->getJSON(true) ?? [];
        $shopId = (int) ($data['shop_id'] ?? 0);
        $amount = (float) ($data['amount'] ?? 0);
        $discountId = (int) ($data['discount_id'] ?? 0);
        if ($shopId < 1 || $amount <= 0) {
            return $this->fail('Invalid input.', 400);
        }

        $shop = db_connect()->table('rewarder_shops')->where('id', $shopId)->where('status', 1)->get()->getRow();
        if (!$shop) {
            return $this->fail('Shop not found.', 404);
        }

        $discount = $this->loadActiveDiscountForShop($shopId, $discountId);
        $calc = $this->calculateDiscount($amount, $discount);
        $reward = $this->calculateRewardPoints($shopId, $amount);

        return $this->ok((object) [
            'amount' => $amount,
            'discount_id' => $discount ? (int) $discount->id : null,
            'discount_amount' => (float) $calc['discount_amount'],
            'payable' => (float) $calc['payable'],
            'eligible' => (bool) $calc['eligible'],
            'reward_points' => (int) $reward['points'],
            'daily_cap' => (int) $reward['daily_cap'],
        ]);
    }

    public function razorpayOrder(): ResponseInterface
    {
        if (!$this->isLoggedIn()) {
            return $this->fail('Login required.', 401);
        }

        $data = $this->request->getJSON(true) ?? [];
        $shopId = (int) ($data['shop_id'] ?? 0);
        $amount = (float) ($data['amount'] ?? 0);
        $discountId = (int) ($data['discount_id'] ?? 0);
        if ($shopId < 1 || $amount <= 0) {
            return $this->fail('Invalid shop or amount.', 400);
        }

        $db = db_connect();
        $shop = $db->table('rewarder_shops')->where('id', $shopId)->where('status', 1)->get()->getRow();
        if (!$shop) {
            return $this->fail('Shop not found.', 404);
        }

        $discount = $this->loadActiveDiscountForShop($shopId, $discountId);
        $calc = $this->calculateDiscount($amount, $discount);
        if ($calc['payable'] <= 0) {
            return $this->fail('Payable must be greater than zero.', 400);
        }

        $amountPaise = (int) round(((float) $calc['payable']) * 100);
        $gateway = (string) setting('payment_gateway', 'razorpay');
        $key = (string) setting('razorpay_key', '');
        $secret = (string) setting('razorpay_secret', '');
        if ($gateway !== 'razorpay' || $key === '' || $secret === '') {
            return $this->fail('Payment gateway not configured.', 500);
        }

        $payload = [
            'amount' => $amountPaise,
            'currency' => 'INR',
            'receipt' => 'shop-' . $shopId . '-' . time(),
            'notes' => [
                'shop_id' => (string) $shopId,
                'user_id' => (string) logged('id'),
                'discount_id' => (string) ($discount ? (int) $discount->id : 0),
            ],
        ];

        $ch = curl_init('https://api.razorpay.com/v1/orders');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_USERPWD, $key . ':' . $secret);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        $resBody = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);

        if ($err) {
            return $this->fail('Order create error.', 500);
        }

        $res = json_decode($resBody, true);
        if ($httpCode >= 200 && $httpCode < 300 && is_array($res) && !empty($res['id'])) {
            return $this->ok((object) [
                'order_id' => (string) $res['id'],
                'amount' => $amountPaise,
                'currency' => 'INR',
                'shop_name' => (string) ($shop->name ?? ''),
                'gross_amount' => (float) $amount,
                'discount_id' => $discount ? (int) $discount->id : null,
                'discount_amount' => (float) $calc['discount_amount'],
                'payable' => (float) $calc['payable'],
            ]);
        }

        $msg = is_array($res) && isset($res['error']) && isset($res['error']['description'])
            ? (string) $res['error']['description']
            : 'Failed to create order.';

        return $this->fail($msg, 500);
    }

    public function razorpayVerify(): ResponseInterface
    {
        if (!$this->isLoggedIn()) {
            return $this->fail('Login required.', 401);
        }

        $data = $this->request->getJSON(true) ?? [];
        $orderId = (string) ($data['order_id'] ?? '');
        $paymentId = (string) ($data['payment_id'] ?? '');
        $signature = (string) ($data['signature'] ?? '');
        $shopId = (int) ($data['shop_id'] ?? 0);
        $grossAmount = (float) ($data['amount'] ?? 0);
        $discountId = (int) ($data['discount_id'] ?? 0);

        if ($orderId === '' || $paymentId === '' || $signature === '') {
            return $this->fail('Invalid verification data.', 400);
        }
        if ($shopId < 1 || $grossAmount <= 0) {
            return $this->fail('Invalid shop or amount.', 400);
        }

        $secret = (string) setting('razorpay_secret', '');
        if ($secret === '') {
            return $this->fail('Payment gateway not configured.', 500);
        }

        $expected = hash_hmac('sha256', $orderId . '|' . $paymentId, $secret);
        if (!hash_equals($expected, $signature)) {
            return $this->fail('Signature verification failed.', 400);
        }

        $db = db_connect();
        $shop = $db->table('rewarder_shops')->where('id', $shopId)->where('status', 1)->get()->getRow();
        if (!$shop) {
            return $this->fail('Shop not found.', 404);
        }

        $discount = $this->loadActiveDiscountForShop($shopId, $discountId);
        $calc = $this->calculateDiscount($grossAmount, $discount);
        $payable = (float) $calc['payable'];
        $discountAmount = (float) $calc['discount_amount'];

        $paymentRowId = model('App\Models\RewarderPaymentModel')->insert([
            'user_id' => logged('id'),
            'shop_id' => $shopId,
            'discount_id' => $discount ? (int) $discount->id : null,
            'amount' => $grossAmount,
            'discount_amount' => $discountAmount,
            'payable' => $payable,
            'gateway' => 'razorpay',
            'gateway_order_id' => $orderId,
            'gateway_payment_id' => $paymentId,
            'gateway_signature' => $signature,
            'status' => 'SUCCESS',
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        $reward = $this->calculateRewardPoints($shopId, $grossAmount);
        $points = (int) $reward['points'];
        $rewardExpireDays = (int) ($reward['reward_points_expire_days'] ?? 0);
        if ($points > 0) {
            $walletModel = new RewarderWalletModel();
            $wallet = $walletModel->where('user_id', logged('id'))->first();
            $nowTs = date('Y-m-d H:i:s');
            $expiryDate = $rewardExpireDays > 0 ? date('Y-m-d', strtotime('+' . $rewardExpireDays . ' days', strtotime($nowTs))) : null;
            if ($wallet) {
                $walletModel->update((int) $wallet->user_id, [
                    'points_balance' => (int) $wallet->points_balance + $points,
                    'updated_at' => $nowTs,
                ]);
            } else {
                $walletModel->insert([
                    'user_id' => (int) logged('id'),
                    'points_balance' => $points,
                    'updated_at' => $nowTs,
                ]);
            }
            (new RewarderLedgerModel())->create([
                'user_id' => (int) logged('id'),
                'shop_id' => $shopId,
                'payment_id' => is_numeric($paymentRowId) ? (int) $paymentRowId : null,
                'order_id' => null,
                'points_delta' => $points,
                'description' => 'Points earned from online bill payment',
                'status' => 1,
                'expiry_date' => $expiryDate,
                'created_at' => $nowTs,
            ]);
            db_connect()->table('users')
                ->where('id', (int) logged('id'))
                ->set('total_reward_point', 'total_reward_point + ' . (int) $points, false)
                ->update();
        }

        return $this->ok((object) [
            'points_earned' => $points,
            'payment_id' => is_numeric($paymentRowId) ? (int) $paymentRowId : null,
            'discount_amount' => $discountAmount,
            'payable' => $payable,
        ]);
    }

    public function phonepeOrder(): ResponseInterface
    {
        if (!$this->isLoggedIn()) {
            return $this->fail('Login required.', 401);
        }

        $data = $this->request->getJSON(true) ?? [];
        $shopId = (int) ($data['shop_id'] ?? 0);
        $amount = (float) ($data['amount'] ?? 0);
        $discountId = (int) ($data['discount_id'] ?? 0);
        if ($shopId < 1 || $amount <= 0) {
            return $this->fail('Invalid shop or amount.', 400);
        }

        $gateway = (string) setting('payment_gateway', 'razorpay');
        if ($gateway !== 'phonepe') {
            return $this->fail('Payment gateway not configured.', 500);
        }
        $phonepe = new PhonePeService();
        if (!$phonepe->isConfigured()) {
            return $this->fail('Payment gateway not configured.', 500);
        }

        $db = db_connect();
        $shop = $db->table('rewarder_shops')->where('id', $shopId)->where('status', 1)->get()->getRow();
        if (!$shop) {
            return $this->fail('Shop not found.', 404);
        }

        $discount = $this->loadActiveDiscountForShop($shopId, $discountId);
        $calc = $this->calculateDiscount($amount, $discount);
        if ($calc['payable'] <= 0) {
            return $this->fail('Payable must be greater than zero.', 400);
        }
        $amountPaise = (int) round(((float) $calc['payable']) * 100);
        if ($amountPaise < 100) {
            return $this->fail('Minimum payable is 1.00.', 400);
        }

        $merchantOrderId = 'MO' . date('YmdHis') . '_' . bin2hex(random_bytes(4));
        $redirectUrl = url('payments/phonepeReturn') . '?mo=' . rawurlencode($merchantOrderId);
        $resp = $phonepe->createCheckout($merchantOrderId, $amountPaise, $redirectUrl);
        if (empty($resp['success'])) {
            return $this->fail((string) ($resp['message'] ?? 'Failed to create order.'), 500);
        }

        (new RewarderPaymentIntentModel())->insert([
            'user_id' => (int) logged('id'),
            'shop_id' => $shopId,
            'discount_id' => $discount ? (int) $discount->id : null,
            'gateway' => 'phonepe',
            'merchant_order_id' => $merchantOrderId,
            'gross_amount' => $amount,
            'discount_amount' => (float) $calc['discount_amount'],
            'payable' => (float) $calc['payable'],
            'amount_paise' => $amountPaise,
            'provider_order_id' => null,
            'state' => 'CREATED',
            'provider_payload' => !empty($resp['raw']) ? json_encode($resp['raw']) : null,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        $orderId = (string) ($resp['order_id'] ?? $merchantOrderId);
        $orderToken = (string) ($resp['order_token'] ?? '');
        $merchantId = (string) ($resp['merchant_id'] ?? setting('phonepe_client_id', ''));

        return $this->ok((object) [
            'order_id' => $orderId,
            'orderId' => $orderId,
            'order_ld' => $orderId,
            'orderld' => $orderId,
            'order_token' => $orderToken,
            'token' => $orderToken,
            'merchant_id' => $merchantId,
            'merchantId' => $merchantId,
            'merchant_order_id' => $merchantOrderId,
            'redirect_url' => (string) $resp['redirect_url'],
            'amount' => $amountPaise,
            'currency' => 'INR',
            'order' => (object) [
                'order_id' => $orderId,
                'orderId' => $orderId,
                'order_ld' => $orderId,
                'orderld' => $orderId,
                'order_token' => $orderToken,
                'token' => $orderToken,
                'merchant_id' => $merchantId,
                'merchantId' => $merchantId,
                'merchant_order_id' => $merchantOrderId,
            ],
        ]);
    }

    public function phonepeStatus(): ResponseInterface
    {
        if (!$this->isLoggedIn()) {
            return $this->fail('Login required.', 401);
        }

        $data = $this->request->getJSON(true) ?? [];
        $merchantOrderId = (string) ($data['merchant_order_id'] ?? '');
        if ($merchantOrderId === '') {
            return $this->fail('Invalid merchant order id.', 400);
        }

        $gateway = (string) setting('payment_gateway', 'razorpay');
        if ($gateway !== 'phonepe') {
            return $this->fail('Payment gateway not configured.', 500);
        }
        $phonepe = new PhonePeService();
        if (!$phonepe->isConfigured()) {
            return $this->fail('Payment gateway not configured.', 500);
        }

        $status = $phonepe->getOrderStatus($merchantOrderId);
        if (empty($status['success'])) {
            return $this->fail('Unable to verify payment status.', 500);
        }
        $raw = $status['raw'] ?? [];
        $state = (string) ($raw['state'] ?? ($raw['data']['state'] ?? ($raw['payload']['state'] ?? '')));
        $amountPaise = (int) ($raw['amount'] ?? ($raw['data']['amount'] ?? ($raw['payload']['amount'] ?? 0)));
        $providerOrderId = (string) ($raw['orderId'] ?? ($raw['data']['orderId'] ?? ($raw['payload']['orderId'] ?? '')));

        $intentModel = new RewarderPaymentIntentModel();
        $intent = $intentModel->where('merchant_order_id', $merchantOrderId)->where('gateway', 'phonepe')->first();
        if ($intent) {
            $intentModel->update((int) $intent->id, [
                'provider_order_id' => $providerOrderId !== '' ? $providerOrderId : ($intent->provider_order_id ?? null),
                'state' => $state !== '' ? $state : ($intent->state ?? 'UNKNOWN'),
                'provider_payload' => !empty($raw) ? json_encode($raw) : ($intent->provider_payload ?? null),
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        }

        if (strtoupper($state) !== 'COMPLETED') {
            return $this->ok((object) [
                'state' => $state,
            ]);
        }

        if ($intent && $amountPaise > 0 && (int) $intent->amount_paise > 0 && $amountPaise !== (int) $intent->amount_paise) {
            return $this->fail('Amount mismatch.', 400);
        }

        $paymentModel = new RewarderPaymentModel();
        $existing = $paymentModel->where('gateway', 'phonepe')->where('gateway_order_id', $merchantOrderId)->where('status', 'SUCCESS')->first();
        if (!$existing && $intent) {
            $paymentRowId = $paymentModel->insert([
                'user_id' => logged('id'),
                'shop_id' => (int) $intent->shop_id,
                'discount_id' => $intent->discount_id ? (int) $intent->discount_id : null,
                'amount' => (float) $intent->gross_amount,
                'discount_amount' => (float) $intent->discount_amount,
                'payable' => (float) $intent->payable,
                'gateway' => 'phonepe',
                'gateway_order_id' => $merchantOrderId,
                'gateway_payment_id' => $providerOrderId !== '' ? $providerOrderId : $merchantOrderId,
                'gateway_signature' => '',
                'status' => 'SUCCESS',
                'created_at' => date('Y-m-d H:i:s'),
            ]);

            $reward = $this->calculateRewardPoints((int) $intent->shop_id, (float) $intent->gross_amount);
            $points = (int) $reward['points'];
            $rewardExpireDays = (int) ($reward['reward_points_expire_days'] ?? 0);
            if ($points > 0) {
                $walletModel = new RewarderWalletModel();
                $wallet = $walletModel->where('user_id', logged('id'))->first();
                $nowTs = date('Y-m-d H:i:s');
                $expiryDate = $rewardExpireDays > 0 ? date('Y-m-d', strtotime('+' . $rewardExpireDays . ' days', strtotime($nowTs))) : null;
                if ($wallet) {
                    $walletModel->update((int) $wallet->user_id, [
                        'points_balance' => (int) $wallet->points_balance + $points,
                        'updated_at' => $nowTs,
                    ]);
                } else {
                    $walletModel->insert([
                        'user_id' => (int) logged('id'),
                        'points_balance' => $points,
                        'updated_at' => $nowTs,
                    ]);
                }
                (new RewarderLedgerModel())->create([
                    'user_id' => (int) logged('id'),
                    'shop_id' => (int) $intent->shop_id,
                    'payment_id' => is_numeric($paymentRowId) ? (int) $paymentRowId : null,
                    'order_id' => null,
                    'points_delta' => $points,
                    'description' => 'Points earned from online bill payment',
                    'status' => 1,
                    'expiry_date' => $expiryDate,
                    'created_at' => $nowTs,
                ]);
                $db = db_connect();
                $db->table('users')
                    ->where('id', (int) logged('id'))
                    ->set('total_reward_point', 'total_reward_point + ' . (int) $points, false)
                    ->update();
            }
        }

        return $this->ok((object) [
            'state' => $state,
            'merchant_order_id' => $merchantOrderId,
        ]);
    }

    private function isLoggedIn(): bool
    {
        return function_exists('is_logged') && is_logged();
    }

    private function loadActiveDiscountForShop(int $shopId, int $discountId)
    {
        if ($discountId < 1) {
            return null;
        }

        $now = date('Y-m-d H:i:s');
        $row = db_connect()->table('rewarder_discounts d')
            ->select('d.*')
            ->where('d.id', $discountId)
            ->where('d.shop_id', $shopId)
            ->where('d.status', 1)
            ->groupStart()->where('d.start_at', null)->orWhere('d.start_at <=', $now)->groupEnd()
            ->groupStart()->where('d.end_at', null)->orWhere('d.end_at >=', $now)->groupEnd()
            ->get()
            ->getRow();

        if (!$row) {
            return null;
        }

        return $this->resolveDiscountScopeLabel($row);
    }

    private function loadActiveRewardRulesForShop(int $shopId): array
    {
        return db_connect()->table('rewarder_reward_rules r')
            ->select('r.points_type, r.value, r.daily_cap')
            ->groupStart()->where('r.shop_id', 0)->orWhere('r.shop_id', $shopId)->groupEnd()
            ->where('r.status', 1)
            ->where('r.applies_to', 'ALL')
            ->orderBy('r.id', 'desc')
            ->get()
            ->getResult();
    }

    private function normalizeRewardRule($r): object
    {
        return (object) [
            'points_type' => (string) ($r->points_type ?? 'FIXED'),
            'value' => (float) ($r->value ?? 0),
            'daily_cap' => isset($r->daily_cap) ? (int) $r->daily_cap : 0,
        ];
    }

    private function calculateDiscount(float $grossAmount, $discount): array
    {
        $dtype = $discount ? (string) ($discount->discount_type ?? 'NONE') : 'NONE';
        $dval = $discount ? (float) ($discount->value ?? 0) : 0.0;
        $minAmount = $discount && !empty($discount->min_amount) ? (float) $discount->min_amount : 0.0;
        $eligible = $minAmount > 0 ? ($grossAmount >= $minAmount) : true;
        $off = 0.0;
        if ($eligible) {
            if ($dtype === 'PERCENT') {
                $off = ($grossAmount * $dval / 100.0);
            } elseif ($dtype !== 'NONE') {
                $off = min($grossAmount, $dval);
            }
        }
        $payable = max($grossAmount - $off, 0.0);

        return [
            'eligible' => $eligible,
            'discount_amount' => $off,
            'payable' => $payable,
        ];
    }

    private function calculateRewardPoints(int $shopId, float $amount): array
    {
        $nowTs = date('Y-m-d H:i:s');
        $rules = (new RewarderRewardRuleModel())
            ->groupStart()->where('shop_id', 0)->orWhere('shop_id', $shopId)->groupEnd()
            ->where('status', 1)
            ->where('applies_to', 'ALL')
            ->orderBy('id', 'desc')
            ->findAll();

        $points = 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 && $amount < $minBill) {
                continue;
            }
            if ($maxBill > 0 && $amount > $maxBill) {
                continue;
            }

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

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

    private function resolveDiscountScopeLabel($discount)
    {
        $scope = (string) ($discount->applies_to ?? 'ALL');
        if ($scope === 'ALL') {
            $discount->scope_label = 'All items/services';
            return $discount;
        }

        $tid = $discount->target_id ?? null;
        $name = null;
        if ($tid) {
            if ($scope === 'PRODUCT') {
                $r = db_connect()->table('rewarder_products')->select('name')->where('id', $tid)->get()->getRow();
                $name = $r ? (string) $r->name : null;
            } elseif ($scope === 'PRODUCT_CATEGORY') {
                $r = db_connect()->table('rewarder_product_categories')->select('name')->where('id', $tid)->get()->getRow();
                $name = $r ? (string) $r->name : null;
            } elseif ($scope === 'SERVICE') {
                $r = db_connect()->table('rewarder_services')->select('name')->where('id', $tid)->get()->getRow();
                $name = $r ? (string) $r->name : null;
            } elseif ($scope === 'SERVICE_CATEGORY') {
                $r = db_connect()->table('rewarder_service_categories')->select('name')->where('id', $tid)->get()->getRow();
                $name = $r ? (string) $r->name : null;
            }
        }
        $discount->scope_label = $name ? (string) $name : ('#' . (string) ($tid ?: ''));
        return $discount;
    }

    private function normalizeDiscount($d): object
    {
        $dtype = (string) ($d->discount_type ?? 'PERCENT');
        $val = (float) ($d->value ?? 0);
        $label = $dtype === 'PERCENT'
            ? (rtrim(rtrim(number_format($val, 2), '0'), '.') . '% off')
            : ('₹' . number_format($val, 2) . ' off');

        $scopeLabel = (string) ($d->scope_label ?? '');
        if ($scopeLabel === '') {
            $scope = (string) ($d->applies_to ?? 'ALL');
            $scopeLabel = $scope === 'ALL' ? 'All items/services' : $scope;
        }

        return (object) [
            'id' => (int) ($d->id ?? 0),
            'shop_id' => (int) ($d->shop_id ?? 0),
            'applies_to' => (string) ($d->applies_to ?? 'ALL'),
            'target_id' => $d->target_id !== null ? (int) $d->target_id : null,
            'discount_type' => $dtype,
            'value' => $val,
            'min_amount' => $d->min_amount !== null ? (float) $d->min_amount : null,
            'start_at' => $d->start_at ?? null,
            'end_at' => $d->end_at ?? null,
            'label' => $label,
            'scope_label' => $scopeLabel,
        ];
    }
}
