<?php

namespace Modules\PurchaseRequisition\Entities\Services;

use DB;
use App\Transaction;
use App\PurchaseLine;
use App\Utils\ProductUtil;
use Illuminate\Support\Str;
use Modules\PurchaseRequisition\Entities\PrRequest;
use Modules\PurchaseRequisition\Entities\PrSupplierProduct;
use Modules\PurchaseRequisition\Entities\PrPurchaseShare;

class PurchaseGenerationService
{
    protected $productUtil;

    public function __construct(ProductUtil $productUtil)
    {
        $this->productUtil = $productUtil;
    }

    /**
     * Generate purchase order from approved requisitions.
     *
     * @param array $prRequestIds
     * @param int $supplierId
     * @param int $locationId
     * @param int $businessId
     * @return Transaction
     * @throws \Exception
     */
    public function generatePurchase(array $prRequestIds, $supplierId, $locationId, $businessId)
    {
        DB::beginTransaction();

        try {
            // Get all approved supplier products for selected requisitions
            $supplierProducts = PrSupplierProduct::whereHas('supplierResponse', function ($query) use ($prRequestIds, $supplierId) {
                    $query->whereIn('pr_request_id', $prRequestIds)
                        ->where('supplier_id', $supplierId)
                        ->where('status', 'approved');
                })
                ->where('approved', true)
                ->with(['prProduct.product', 'prProduct.variation', 'supplierResponse.currency'])
                ->get();

            if ($supplierProducts->isEmpty()) {
                throw new \Exception('No approved products found for the selected requisitions.');
            }

            // Generate reference number
            $refCount = $this->productUtil->setAndGetReferenceCount('purchase', $businessId);
            $refNo = $this->productUtil->generateReferenceNumber('purchase', $refCount, $businessId);

            // Create transaction record
            $transaction = Transaction::create([
                'business_id' => $businessId,
                'location_id' => $locationId,
                'type' => 'purchase',
                'status' => 'ordered', // Draft/pending purchase order
                'payment_status' => 'due',
                'contact_id' => $supplierId,
                'ref_no' => $refNo,
                'transaction_date' => now(),
                'total_before_tax' => 0, // Will be calculated
                'final_total' => 0, // Will be calculated
                'created_by' => auth()->user()->id,
            ]);

            $totalAmount = 0;

            // Create purchase lines
            foreach ($supplierProducts as $supplierProduct) {
                $prProduct = $supplierProduct->prProduct;
                $quantity = $supplierProduct->available_qty;
                $unitPrice = $supplierProduct->converted_price_egp;
                $lineTotal = $quantity * $unitPrice;

                PurchaseLine::create([
                    'transaction_id' => $transaction->id,
                    'product_id' => $prProduct->product_id,
                    'variation_id' => $prProduct->variation_id,
                    'quantity' => $quantity,
                    'pp_without_discount' => $unitPrice,
                    'purchase_price' => $unitPrice,
                    'purchase_price_inc_tax' => $unitPrice,
                    'discount_percent' => 0,
                    'item_tax' => 0,
                    'tax_id' => null,
                    'purchase_requisition_line_id' => $prProduct->id,
                    'lot_number' => $refNo,
                ]);

                $totalAmount += $lineTotal;
            }

            // Update transaction totals
            $transaction->update([
                'total_before_tax' => $totalAmount,
                'final_total' => $totalAmount,
            ]);

            // Update requisition statuses to completed
            PrRequest::whereIn('id', $prRequestIds)
                ->update(['status' => 'completed']);

            // Create share record for public read-only link
            PrPurchaseShare::create([
                'business_id'    => $businessId,
                'transaction_id' => $transaction->id,
                'pr_request_ids' => $prRequestIds,
                'share_token'    => Str::random(64),
            ]);

            DB::commit();

            return $transaction;

        } catch (\Exception $e) {
            DB::rollBack();
            \Log::emergency('File:' . $e->getFile() . ' Line:' . $e->getLine() . ' Message:' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Export purchase to CSV format.
     *
     * @param int $transactionId
     * @return string CSV content
     */
    public function exportToCsv($transactionId)
    {
        $transaction = Transaction::with(['purchase_lines.product', 'purchase_lines.variation'])->find($transactionId);

        if (!$transaction) {
            throw new \Exception('Transaction not found.');
        }

        $csv = "Product,SKU,Variation,Quantity,Unit Price,Total\n";

        foreach ($transaction->purchase_lines as $line) {
            $product = $line->product;
            $variation = $line->variation;

            $productName = $product->name ?? '';
            $sku = $variation->sub_sku ?? $product->sku ?? '';
            $variationName = $variation->product_variation->name ?? '';
            $quantity = $line->quantity;
            $unitPrice = $line->purchase_price;
            $total = $quantity * $unitPrice;

            $csv .= "\"{$productName}\",\"{$sku}\",\"{$variationName}\",{$quantity},{$unitPrice},{$total}\n";
        }

        return $csv;
    }

    /**
     * Group products by supplier for multiple requisitions.
     *
     * @param array $prRequestIds
     * @return array
     */
    public function groupProductsBySupplier(array $prRequestIds)
    {
        $supplierProducts = PrSupplierProduct::whereHas('supplierResponse', function ($query) use ($prRequestIds) {
                $query->whereIn('pr_request_id', $prRequestIds)
                    ->where('status', 'approved');
            })
            ->where('approved', true)
            ->with(['prProduct', 'supplierResponse.supplier'])
            ->get();

        $grouped = [];

        foreach ($supplierProducts as $supplierProduct) {
            $supplierId = $supplierProduct->supplierResponse->supplier_id;
            $supplierContact = $supplierProduct->supplierResponse->supplier;
            $supplierName = ($supplierContact ? ($supplierContact->name ?: $supplierContact->supplier_business_name) : null) ?: 'Unknown';

            if (!isset($grouped[$supplierId])) {
                $grouped[$supplierId] = [
                    'supplier_id' => $supplierId,
                    'supplier_name' => $supplierName,
                    'products' => [],
                    'total_amount' => 0,
                ];
            }

            $grouped[$supplierId]['products'][] = $supplierProduct;
            $grouped[$supplierId]['total_amount'] += ($supplierProduct->available_qty * $supplierProduct->converted_price_egp);
        }

        return $grouped;
    }

    /**
     * Validate purchase generation request.
     *
     * @param array $prRequestIds
     * @param int $supplierId
     * @return array Validation result
     */
    public function validatePurchaseGeneration(array $prRequestIds, $supplierId)
    {
        $errors = [];

        // Check if requisitions exist and are approved
        $requests = PrRequest::whereIn('id', $prRequestIds)->get();

        if ($requests->isEmpty()) {
            $errors[] = 'No purchase requisitions found.';
            return ['valid' => false, 'errors' => $errors];
        }

        foreach ($requests as $request) {
            if ($request->status !== 'approved') {
                $errors[] = "Purchase requisition {$request->ref_no} is not approved.";
            }
        }

        // Check if supplier has approved products
        $approvedCount = PrSupplierProduct::whereHas('supplierResponse', function ($query) use ($prRequestIds, $supplierId) {
                $query->whereIn('pr_request_id', $prRequestIds)
                    ->where('supplier_id', $supplierId)
                    ->where('status', 'approved');
            })
            ->where('approved', true)
            ->count();

        if ($approvedCount == 0) {
            $errors[] = 'No approved products found for this supplier.';
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors,
        ];
    }
}
