<?php

namespace App\Services;

use App\Helpers\VisitorHelper;
use App\Models\Client;
use App\Models\Currency;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class DiscountManager
{
    protected $clientDiscountService;

    protected $couponValidationService;

    protected $visitorService;

    public function __construct(
        ClientDiscountService $clientDiscountService,
        CouponValidationService $couponValidationService,
        VisitorService $visitorService
    ) {
        $this->clientDiscountService = $clientDiscountService;
        $this->couponValidationService = $couponValidationService;
        $this->visitorService = $visitorService;
    }

    /**
     * Tüm indirimleri hesapla ve en iyi olanı seç
     * Priority: Client Discounts > Coupons
     */
    public function calculateBestDiscount(
        array $basketItems,
        Currency $currency,
        ?Request $request = null
    ): array {
        $client = $request?->user();
        $discountResults = [];

        // 1. Client-specific discounts (highest priority)
        if ($client) {
            $clientDiscounts = $this->clientDiscountService->calculateClientDiscounts(
                $client,
                $basketItems,
                $currency
            );

            if ($clientDiscounts['discount_amount'] > 0) {
                $discountResults[] = [
                    'type' => 'client_specific',
                    'priority' => 1,
                    'discount_amount' => $clientDiscounts['discount_amount'],
                    'discount_text' => __('admin/common.services_discount_client_specific'),
                    'applied_discounts' => $clientDiscounts['applied_discounts'],
                    'total_savings' => $clientDiscounts['total_savings'],
                ];
            }
        }

        // 2. Coupon discounts
        if ($request) {
            $couponDiscount = $this->calculateCouponDiscount($basketItems, $request, $client, $currency);

            if ($couponDiscount['discount_amount'] > 0) {
                $discountResults[] = [
                    'type' => 'coupon',
                    'priority' => 2,
                    'discount_amount' => $couponDiscount['discount_amount'],
                    'discount_text' => $couponDiscount['discount_text'] ?? __('admin/common.services_discount_coupon'),
                    'coupon_code' => $couponDiscount['coupon_code'] ?? null,
                    'total_savings' => $couponDiscount['discount_amount'],
                ];
            }
        }

        // 3. PRC-440 — Auto-applied promotions. Promotions (coupons'tan farklı)
        // kod girmeden, kriter eşleşince otomatik uygulanır
        // (docs/features/PROMOTIONS.md). Eskiden DiscountManager hiç
        // promotion işlemiyordu → cart'ta indirim oluşmuyordu, manuel kod
        // girişi de coupon flow'una düşüp yanıltıcı "uygulandı" mesajı
        // veriyordu (PRC-440 Problem 1 + 2).
        $promotionDiscount = $this->calculatePromotionDiscount($basketItems, $client, $currency);
        if ($promotionDiscount['discount_amount'] > 0) {
            $discountResults[] = [
                'type' => 'promotion',
                'priority' => 3,
                'discount_amount' => $promotionDiscount['discount_amount'],
                'discount_text' => $promotionDiscount['discount_text'] ?? __('admin/common.services_discount_promotion'),
                // PRC-577 — Promotion'lar auto-apply'dır, kullanıcının girip
                // kaldırabildiği kupon DEĞİL. `coupon_code` summary'de yalnız
                // kaldırılabilir kuponu temsil eder; promotion'ı buraya yazmak
                // frontend'de sahte "kaldırılabilir kupon" chip'i üretiyordu
                // (remove no-op → indirim geri gelir). Promosyon kimliği
                // `discount_text` ile taşınır. Bu yüzden coupon_code = null.
                'coupon_code' => null,
                // PRC-579 — promotion kimliği (checkout usage kaydı için summary'ye taşınır).
                'promotion_code' => $promotionDiscount['promotion_code'] ?? null,
                'total_savings' => $promotionDiscount['discount_amount'],
            ];
        }

        // En yüksek öncelikli ve en yüksek tutarlı indirimi seç
        $bestDiscount = $this->selectBestDiscount($discountResults);

        return $bestDiscount ?: [
            'type' => 'none',
            'priority' => 0,
            'discount_amount' => 0,
            'discount_text' => null,
            'total_savings' => 0,
        ];
    }

    /**
     * PRC-440 — Auto-applied promotion discount. Active + tarih aralığında
     * olan promotion'lar arasında en yüksek indirimi seçer. Promotion'lar
     * code-free auto-apply'dır; her active promotion'ın kendi `target_type`
     * (all / specific_products / specific_groups) mantığı Promotion modelinde.
     */
    protected function calculatePromotionDiscount(array $basketItems, ?Client $client, Currency $currency): array
    {
        $now = now();

        $promotions = \App\Models\Promotion::where('status', 'active')
            ->where(function ($q) use ($now) {
                $q->whereNull('start_date')->orWhere('start_date', '<=', $now);
            })
            ->where(function ($q) use ($now) {
                $q->whereNull('end_date')->orWhere('end_date', '>=', $now);
            })
            ->get();

        if ($promotions->isEmpty()) {
            return ['discount_amount' => 0];
        }

        // Sepet ara toplamı (price * quantity). Promotion modeli target
        // bazlı hesaplamada basketItems'ı kendi parse eder.
        $subtotal = collect($basketItems)->sum(function ($i) {
            $price = $i['price'] ?? $i['amount'] ?? 0;
            $qty = $i['quantity'] ?? 1;
            return (float) $price * (int) $qty;
        });

        $best = ['discount_amount' => 0];
        foreach ($promotions as $promo) {
            // PRC-579 — admin'de ayarlanan kuralları enforce et (limit +
            // müşteri-tipi + per-client). Uygun değilse aday değil.
            if (! $this->isPromotionEligible($promo, $client)) {
                continue;
            }

            // PRC-1099 currency-scope guard (kupon PRC-510 ile ayni sozlesme); currency_id NULL => currency-agnostik, atlanir.
            if ($promo->currency_id && $currency && $promo->currency_id != $currency->id) {
                continue;
            }

            $discount = (float) $promo->calculateDiscount($subtotal, $basketItems);
            if ($discount > $best['discount_amount']) {
                $best = [
                    'discount_amount' => round($discount, 2),
                    'discount_text' => $promo->name ?? $promo->code,
                    'promotion_code' => $promo->code,
                ];
            }
        }

        return $best;
    }

    /**
     * PRC-809 — Renewal faturası için promosyon indirimi. Tek client_product
     * yenilenirken uygulanabilir promosyonları (active + tarih + allow_renewal +
     * !only_new_orders) değerlendirir; cycles (kaç yenileme döngüsü indirim) bu
     * client_product için PromotionUsage sayısıyla enforce edilir; targeting/limit/
     * per-client `isPromotionEligible('renewal')` ile ORTAK (ayrı kod yolu yok).
     * Renewal indirimi için allow_renewal=true AND cycles>0 gerekir; cycles null/0
     * = yalnız yeni sipariş. En yüksek indirimi döndürür.
     *
     * @return array{discount_amount: float, promotion_id?: int, promotion_code?: ?string, promotion_name?: ?string}
     */
    public function calculateRenewalDiscount(\App\Models\ClientProduct $clientProduct, float $amount, ?Client $client, ?Currency $currency = null): array
    {
        if ($amount <= 0) {
            return ['discount_amount' => 0];
        }

        $now = now();
        $promotions = \App\Models\Promotion::where('status', 'active')
            ->where('allow_renewal', true)
            ->where('only_new_orders', false)
            ->where(function ($q) use ($now) {
                $q->whereNull('start_date')->orWhere('start_date', '<=', $now);
            })
            ->where(function ($q) use ($now) {
                $q->whereNull('end_date')->orWhere('end_date', '>=', $now);
            })
            ->get();

        if ($promotions->isEmpty()) {
            return ['discount_amount' => 0];
        }

        // calculateDiscount targeting'i (all/specific_products/specific_groups)
        // sepet item'ı üzerinden yapar — tek yenilenen ürünü modelle.
        $basketItem = ['type' => 'product', 'product_id' => $clientProduct->product_id, 'price' => $amount];

        $best = ['discount_amount' => 0];
        foreach ($promotions as $promo) {
            if (! $this->isPromotionEligible($promo, $client, 'renewal')) {
                continue;
            }

            // PRC-1099 currency-scope guard (kupon PRC-510 ile ayni sozlesme); currency_id NULL => currency-agnostik, atlanir.
            if ($promo->currency_id && $currency && $promo->currency_id != $currency->id) {
                continue;
            }

            // cycles: null/0 → renewal'da uygulanmaz; >0 → ilk N yenilemede.
            $cycles = (int) $promo->cycles;
            if ($cycles <= 0) {
                continue;
            }
            $renewalUses = \App\Models\PromotionUsage::where('promotion_id', $promo->id)
                ->where('client_product_id', $clientProduct->id)
                ->count();
            if ($renewalUses >= $cycles) {
                continue;
            }

            $discount = (float) $promo->calculateDiscount($amount, [$basketItem]);
            if ($discount > $best['discount_amount']) {
                $best = [
                    'discount_amount' => round($discount, 2),
                    'promotion_id' => $promo->id,
                    'promotion_code' => $promo->code,
                    'promotion_name' => $promo->name,
                ];
            }
        }

        return $best;
    }

    /**
     * PRC-579 — Promosyon uygunluk kontrolü (Ürün Hesaplama hattı).
     * status + tarih penceresi DB sorgusunda elendi; burada admin'in
     * ayarladığı kalan kuralları uygula:
     *  - `limit`: toplam kullanım (`uses >= limit`) dolduysa uygun değil.
     *  - `only_new_client`: ödenmiş faturası olan müşteriye uygulanmaz
     *    (misafir = yeni sayılır, geçer).
     *  - `only_existing_client`: misafir veya yeni müşteriye uygulanmaz.
     *  - `only_once_client` / `usage_limit_per_client`: kimliği belli
     *    müşteride `promotion_usages` sayımı limiti aşmışsa uygulanmaz.
     *    Misafirde kimlik olmadığından per-client enforce edilemez (geçer).
     * PRC-809 — renewal bağlamı artık BAĞLI: `$context='renewal'` iken
     * allow_renewal/only_new_orders burada enforce edilir; cycles renewal
     * sayacı `calculateRenewalDiscount`'ta (DueInvoiceService çağırır). allow_upgrades
     * hâlâ upgrade bağlamında (buradan geçmez); is_combinable ise selectBestDiscount
     * tek indirim seçtiği için fiilen no-op.
     */
    private function isPromotionEligible(\App\Models\Promotion $promo, ?Client $client, string $context = 'new_order'): bool
    {
        // PRC-809 — renewal bağlamı: yalnız allow_renewal promosyonlar ve
        // only_new_orders olmayanlar renewal faturasına uygulanır. (new_order
        // bağlamında bu iki alan kısıt değildir — davranış değişmez.)
        if ($context === 'renewal') {
            if (! $promo->allow_renewal || $promo->only_new_orders) {
                return false;
            }
        }

        // Toplam kullanım limiti
        if ($promo->limit !== null && $promo->uses >= $promo->limit) {
            return false;
        }

        $isNewClient = $client ? ! $client->invoices()->where('status', 'paid')->exists() : true;

        if ($promo->only_new_client && ! $isNewClient) {
            return false;
        }
        if ($promo->only_existing_client && ($client === null || $isNewClient)) {
            return false;
        }

        // Müşteri-bazlı kullanım limiti (yalnız kimliği belli müşteri için)
        if ($client) {
            $perClientLimit = $promo->only_once_client ? 1 : $promo->usage_limit_per_client;
            if ($perClientLimit !== null) {
                $used = \App\Models\PromotionUsage::where('promotion_id', $promo->id)
                    ->where('client_id', $client->id)
                    ->count();
                if ($used >= $perClientLimit) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * En iyi indirimi seç (öncelik sırasına göre, sonra tutara göre)
     */
    protected function selectBestDiscount(array $discountResults): ?array
    {
        if (empty($discountResults)) {
            return null;
        }

        // Öncelik sırasına göre sırala, sonra tutar'a göre
        usort($discountResults, function ($a, $b) {
            if ($a['priority'] === $b['priority']) {
                return $b['discount_amount'] <=> $a['discount_amount']; // Yüksek tutar önce
            }

            return $a['priority'] <=> $b['priority']; // Düşük priority sayısı önce (yüksek öncelik)
        });

        return $discountResults[0];
    }

    /**
     * Coupon discount hesapla
     */
    protected function calculateCouponDiscount(array $basketItems, Request $request, ?Client $client, Currency $currency = null): array
    {
        $visitorId = VisitorHelper::getVisitorId($request);
        $visitorData = $visitorId ? VisitorHelper::getVisitorDetails($visitorId) : [];

        // Visitor'dan coupon code al
        $couponCode = $visitorId ? \App\Helpers\VisitorHelper::getVisitorBasketCoupon($visitorId) : null;

        if (! $couponCode) {
            return [
                'discount_amount' => 0,
                'discount_text' => null,
                'coupon_code' => null,
            ];
        }

        // Get currency from visitor if not provided
        if (!$currency) {
            $currency = Currency::find($visitorData['currency_id'] ?? 1);
        }

        $couponValidation = $this->couponValidationService->validateCouponForBasket(
            $couponCode,
            $basketItems,
            $visitorData,
            $client,
            $currency
        );

        if ($couponValidation['valid']) {
            return [
                'discount_amount' => $couponValidation['discount_amount'],
                'discount_text' => $couponValidation['discount_text'],
                'coupon_code' => $couponCode,
            ];
        }

        return [
            'discount_amount' => 0,
            'discount_text' => null,
            'coupon_code' => $couponCode,
        ];
    }

    /**
     * Visitor-client sync sonrası tüm indirimleri güncelle
     */
    public function syncAllDiscountsWithVisitor(Client $client, string $visitorId): void
    {
        // Client discount'ları sync et
        $this->clientDiscountService->syncClientDiscountsWithVisitor($client, $visitorId);

        Log::info('All discounts synced with visitor after login', [
            'client_id' => $client->id,
            'visitor_id' => $visitorId,
        ]);
    }

    /**
     * Sepette uygulanan indirim bilgilerini al - Updated for basket structure
     */
    public function getAppliedDiscountInfo(?Request $request = null): array
    {
        if (! $request) {
            return [
                'has_discount' => false,
                'discount_type' => null,
                'discount_amount' => 0,
                'discount_text' => null,
            ];
        }

        // Use 'client' guard for store
        $client = auth()->guard('client')->user();
        $visitorId = VisitorHelper::getVisitorId($request);

        // Visitor details'dan aktif indirim bilgilerini al
        $visitorDetails = VisitorHelper::getVisitorDetails($visitorId) ?? [];

        // Coupon kodu kontrolü - YENİ SEPET YAPISINDAN AL
        $couponCode = null;
        if ($visitorId) {
            $couponCode = VisitorHelper::getVisitorBasketCoupon($visitorId);
        }

        return [
            'has_discount' => ! empty($couponCode) || ! empty($visitorDetails['client_discounts'] ?? []),
            'coupon_code' => $couponCode,
            'client_discounts' => $visitorDetails['client_discounts'] ?? [],
            'client_id' => $client?->id,
        ];
    }

    /**
     * İndirim istatistiklerini al
     */
    public function getDiscountStats(?Client $client = null): array
    {
        $stats = [
            'total_discount_types' => 1, // En az coupon var
            'client_specific_discounts' => 0,
            'available_coupons' => 1, // Coupon sistemi mevcut
        ];

        if ($client) {
            $clientStats = $this->clientDiscountService->getClientDiscountStats($client);
            $stats['client_specific_discounts'] = $clientStats['active_discounts'];
            $stats['total_discount_types']++;
        }

        return $stats;
    }

    /**
     * İndirim kurallarını doğrula (admin panel için)
     */
    public function validateDiscountRules(array $discountData, string $discountType): array
    {
        $errors = [];

        // Genel doğrulamalar
        if (empty($discountData['name'])) {
            $errors[] = __('admin/common.services_validation_discount_name_required');
        }

        if (! in_array($discountData['type'] ?? '', ['percentage', 'fixed_amount'])) {
            $errors[] = __('admin/common.services_validation_discount_type_invalid');
        }

        if (($discountData['discount_value'] ?? 0) <= 0) {
            $errors[] = __('admin/common.services_validation_discount_value_min');
        }

        if ($discountData['type'] === 'percentage' && ($discountData['discount_value'] ?? 0) > 100) {
            $errors[] = __('admin/common.services_validation_discount_percentage_max');
        }

        if ($discountData['type'] === 'fixed_amount' && empty($discountData['currency_id'])) {
            $errors[] = __('admin/common.services_validation_discount_currency_required');
        }

        // Tarih doğrulaları
        if (! empty($discountData['starts_at']) && ! empty($discountData['expires_at'])) {
            if (strtotime($discountData['starts_at']) >= strtotime($discountData['expires_at'])) {
                $errors[] = __('admin/common.services_validation_discount_date_range');
            }
        }

        // Tip-specific doğrulamalar
        if ($discountType === 'client_specific' && empty($discountData['client_id'])) {
            $errors[] = __('admin/common.services_validation_discount_client_required');
        }

        return $errors;
    }
}
