<?php

namespace App\Services;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Product;
use App\Models\Setting;
use Illuminate\Support\Collection;

class ProfitService
{
    protected TaxService $taxService;

    public function __construct(TaxService $taxService)
    {
        $this->taxService = $taxService;
    }
    /**
     * Calculate and allocate costs when creating order items
     *
     * @param Order $order
     * @param array $items
     * @return void
     */
    public function allocateOrderCosts(Order $order, array $items): void
    {
        $totalLineValue = collect($items)->sum(fn($item) => $item['price'] * $item['qty']);
        
        foreach ($items as $itemData) {
            $product = Product::find($itemData['product_id']);
            $lineTotal = $itemData['price'] * $itemData['qty'];
            
            // Calculate item-level discount from discount_percentage
            $discountPercentage = $itemData['discount_percentage'] ?? 0;
            $itemDiscount = $lineTotal * ($discountPercentage / 100);
            
            // Calculate pro-rata allocations for shipping (discount is now item-level)
            $allocationRatio = $totalLineValue > 0 ? $lineTotal / $totalLineValue : 0;
            
            $allocatedDiscount = round($itemDiscount, 2);
            $allocatedShipping = round($order->shipping_total * $allocationRatio, 2);
            $allocatedExtraCosts = 0; // Can be extended for other order-level costs
            
            // Unified model: product is the actual sellable item
            // Get purchase price from product
            $purchasePrice = $this->getPurchasePriceForOrder($product);
            $sku = $product->sku ?? $product->item_code ?? $product->barcode ?? $product->slug;
            $name = $product->name;
            
            // Calculate tax for this line item
            $taxRate = $this->taxService->getTaxRateForItem($product, null);
            $taxAmount = $this->taxService->calculateItemTax(
                $itemData['price'],
                $itemData['qty'],
                $taxRate
            );
            
            // Create order item with profit data and tax
            OrderItem::create([
                'order_id' => $order->id,
                'product_id' => $product->id,
                'name' => $name,
                'sku' => $sku,
                'qty' => $itemData['qty'],
                'price' => $itemData['price'],
                'discount_percentage' => $discountPercentage,
                'line_total' => $lineTotal,
                'tax_amount' => round($taxAmount, 2),
                'purchase_price' => $purchasePrice,
                'allocated_discount' => $allocatedDiscount,
                'allocated_shipping' => $allocatedShipping,
                'allocated_extra_costs' => $allocatedExtraCosts,
            ]);
        }
        
        // Aggregate all line item tax amounts and update order tax_total
        $totalTax = OrderItem::where('order_id', $order->id)
            ->sum('tax_amount');
        $order->update(['tax_total' => round($totalTax, 2)]);
    }

    /**
     * Get purchase price for order based on fallback policy
     *
     * @param Product $product
     * @return float|null
     */
    private function getPurchasePriceForOrder(Product $product): ?float
    {
        if ($product->hasPurchasePrice()) {
            return $product->purchase_price;
        }

        $fallbackPolicy = Setting::where('key', 'profit_purchase_price_fallback_policy')
            ->value('value') ?? 'mark_zero_and_flag';

        switch ($fallbackPolicy) {
            case 'block_checkout':
                throw new \Exception("Product {$product->name} is missing purchase price. Checkout blocked.");
            
            case 'use_last_known':
                // Could implement purchase history lookup here
                return 0;
            
            case 'mark_zero_and_flag':
            default:
                return null; // Will be flagged in reports
        }
    }

    /**
     * @deprecated No longer needed - variants are now Products, use getPurchasePriceForOrder instead
     */

    /**
     * Calculate profit metrics for a collection of order items
     *
     * @param Collection $orderItems
     * @return array
     */
    public function calculateProfitMetrics(Collection $orderItems): array
    {
        $totalRevenue = 0;
        $totalCogs = 0;
        $totalProfit = 0;
        $itemsWithProfitData = 0;
        $totalItems = $orderItems->count();

        foreach ($orderItems as $item) {
            $totalRevenue += $item->revenue;
            
            if ($item->hasProfitData()) {
                $totalCogs += $item->total_cogs;
                $totalProfit += $item->total_profit;
                $itemsWithProfitData++;
            }
        }

        $profitMargin = $totalRevenue > 0 ? round(($totalProfit / $totalRevenue) * 100, 2) : 0;

        return [
            'total_revenue' => round($totalRevenue, 2),
            'total_cogs' => round($totalCogs, 2),
            'total_profit' => round($totalProfit, 2),
            'profit_margin_percent' => $profitMargin,
            'items_with_profit_data' => $itemsWithProfitData,
            'total_items' => $totalItems,
            'profit_data_coverage_percent' => $totalItems > 0 ? round(($itemsWithProfitData / $totalItems) * 100, 2) : 0
        ];
    }

    /**
     * Get profit report data with filters
     *
     * @param array $filters
     * @return array
     */
    public function getProfitReport(array $filters = []): array
    {
        $query = OrderItem::with(['order', 'product'])
            ->whereHas('order', function ($q) use ($filters) {
                if (!empty($filters['start_date'])) {
                    $q->where('created_at', '>=', $filters['start_date']);
                }
                if (!empty($filters['end_date'])) {
                    $q->where('created_at', '<=', $filters['end_date']);
                }
                if (!empty($filters['order_status'])) {
                    $q->where('status', $filters['order_status']);
                }
                if (!empty($filters['payment_status'])) {
                    $q->where('payment_status', $filters['payment_status']);
                }
                if (!empty($filters['staff_id'])) {
                    $q->where('staff_id', $filters['staff_id']);
                }
                if (!empty($filters['source'])) {
                    $q->where('source', $filters['source']);
                }
                if (!empty($filters['exclude_statuses'])) {
                    $q->whereNotIn('status', $filters['exclude_statuses']);
                }
            });

        if (!empty($filters['product_id'])) {
            $query->where('product_id', $filters['product_id']);
        }

        if (!empty($filters['category_id'])) {
            $query->whereHas('product', function ($q) use ($filters) {
                $q->where('category_id', $filters['category_id']);
            });
        }

        $orderItems = $query->get();
        
        return $this->calculateProfitMetrics($orderItems);
    }

    /**
     * Get profit by product report
     *
     * @param array $filters
     * @return Collection
     */
    public function getProfitByProduct(array $filters = []): Collection
    {
        $query = OrderItem::with(['product'])
            ->whereHas('order', function ($q) use ($filters) {
                if (!empty($filters['start_date'])) {
                    $q->where('created_at', '>=', $filters['start_date']);
                }
                if (!empty($filters['end_date'])) {
                    $q->where('created_at', '<=', $filters['end_date']);
                }
                if (!empty($filters['order_status'])) {
                    $q->where('status', $filters['order_status']);
                }
                if (!empty($filters['payment_status'])) {
                    $q->where('payment_status', $filters['payment_status']);
                }
                if (!empty($filters['staff_id'])) {
                    $q->where('staff_id', $filters['staff_id']);
                }
            })
            ->whereNotNull('purchase_price');

        if (!empty($filters['category_id'])) {
            $query->whereHas('product', function ($q) use ($filters) {
                $q->where('category_id', $filters['category_id']);
            });
        }

        return $query->get()
            ->groupBy('product_id')
            ->map(function ($items, $productId) {
                $product = $items->first()->product;
                $totalQty = $items->sum('qty');
                $totalRevenue = $items->sum('revenue');
                $totalCogs = $items->sum('total_cogs');
                $totalProfit = $items->sum('total_profit');
                $profitMargin = $totalRevenue > 0 ? round(($totalProfit / $totalRevenue) * 100, 2) : 0;

                return [
                    'product_id' => $productId,
                    'product_name' => $product?->name ?? '',
                    'sku' => $product?->barcode ?? $product?->slug ?? '',
                    'units_sold' => $totalQty,
                    'total_revenue' => round($totalRevenue, 2),
                    'total_cogs' => round($totalCogs, 2),
                    'gross_profit' => round($totalProfit, 2),
                    'margin_percent' => $profitMargin,
                ];
            })
            ->sortByDesc('gross_profit')
            ->values();
    }

    /**
     * Get top profitable and loss-making products
     *
     * @param int $limit
     * @param array $filters
     * @return array
     */
    public function getTopProfitableProducts(int $limit = 10, array $filters = []): array
    {
        $products = $this->getProfitByProduct($filters);

        return [
            'most_profitable' => $products->take($limit),
            'least_profitable' => $products->sortBy('gross_profit')->take($limit)->values(),
        ];
    }
}