<?php

namespace App\Services\Sales;

use App\Services\BaseService;
use App\Repositories\SalesOrderRepository;
use App\Models\SalesOrder;
use App\Models\SalesOrderItem;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Barryvdh\DomPDF\Facade\Pdf;

class SalesOrderService extends BaseService
{
    protected SalesOrderRepository $salesOrderRepository;

    public function __construct(SalesOrderRepository $repository)
    {
        parent::__construct($repository);
        $this->salesOrderRepository = $repository;
    }

    /**
     * Get all sales orders with relations
     */
    public function getAllWithRelations(): Collection
    {
        return $this->salesOrderRepository->getAllWithRelations();
    }

    /**
     * Get sales orders by customer
     */
    public function getByCustomer(int $customerId): Collection
    {
        return $this->salesOrderRepository->getByCustomer($customerId);
    }

    /**
     * Get sales orders by status
     */
    public function getByStatus(string $status): Collection
    {
        return $this->salesOrderRepository->getByStatus($status);
    }

    /**
     * Get active sales orders
     */
    public function getActive(): Collection
    {
        return $this->salesOrderRepository->getActive();
    }

    /**
     * Get sales orders by date range
     */
    public function getByDateRange(string $startDate, string $endDate): Collection
    {
        return $this->salesOrderRepository->getByDateRange($startDate, $endDate);
    }

    /**
     * Create sales order from quotation
     */
    public function createFromQuotation(int $quotationId, array $additionalData = []): SalesOrder
    {
        return DB::transaction(function () use ($quotationId, $additionalData) {
            $quotation = \App\Models\Quotation::with('customer')->findOrFail($quotationId);

            $data = [
                'sales_order_no' => $this->generateSalesOrderNumber(),
                'sales_order_date' => now()->toDateString(),
                'customer_ref_no' => $quotation->cust_ref_no,
                'company_name' => $quotation->customer_name,
                'company_address' => $quotation->address,
                'company_gstn' => $quotation->gst,
                'company_phone' => $quotation->phone,
                'company_email' => $quotation->email,
                'quotation_no' => $quotation->quotation_no,
                'quotation_date' => $quotation->quotation_date,
                'rfq_no' => $quotation->rfq_no,
                'rfq_date' => $quotation->rfq_date,
                'part_no' => $quotation->part_no,
                'project_material_no' => $quotation->project_material_no,
                'drawing_no' => $quotation->drawing_no,
                'drawing_rev' => $quotation->drawing_rev,
                'description' => $quotation->description,
                'product_type' => $quotation->product_type,
                'status' => 'Pending',
            ];

            // Merge additional data
            $data = array_merge($data, $additionalData);

            $salesOrder = $this->salesOrderRepository->create($data);

            $this->logAction('created Sales Order from Quotation', [
                'sales_order_id' => $salesOrder->id,
                'sales_order_no' => $salesOrder->sales_order_no,
                'quotation_id' => $quotationId,
            ]);

            return $salesOrder;
        });
    }

    /**
     * Create sales order with items
     */
    public function createWithItems(array $data, array $items = []): SalesOrder
    {
        return DB::transaction(function () use ($data, $items) {
            // Generate sales order number if not provided
            if (empty($data['sales_order_no'])) {
                $data['sales_order_no'] = $this->generateSalesOrderNumber();
            }

            // Calculate totals
            $data = $this->calculateTotals($data, $items);

            $salesOrder = $this->salesOrderRepository->create($data);

            // Create items
            if (!empty($items)) {
                $this->createItems($salesOrder, $items);
            }

            $this->logAction('created Sales Order', [
                'sales_order_id' => $salesOrder->id,
                'sales_order_no' => $salesOrder->sales_order_no,
            ]);

            return $salesOrder->load('items');
        });
    }

    /**
     * Update sales order with items
     */
    public function updateWithItems(int $id, array $data, array $items = []): SalesOrder
    {
        return DB::transaction(function () use ($id, $data, $items) {
            // Calculate totals
            $data = $this->calculateTotals($data, $items);

            $salesOrder = $this->salesOrderRepository->update($id, $data);

            // Update items
            if (!empty($items)) {
                // Delete existing items
                $salesOrder->items()->delete();
                // Create new items
                $this->createItems($salesOrder, $items);
            }

            $this->logAction('updated Sales Order', [
                'sales_order_id' => $salesOrder->id,
                'sales_order_no' => $salesOrder->sales_order_no,
            ]);

            return $salesOrder->load('items');
        });
    }

    /**
     * Create items for sales order
     */
    protected function createItems(SalesOrder $salesOrder, array $items): void
    {
        foreach ($items as $index => $item) {
            SalesOrderItem::create([
                'sales_order_id' => $salesOrder->id,
                'sl_no' => $index + 1,
                'description' => $item['description'] ?? '',
                'hsn' => $item['hsn'] ?? '',
                'quantity' => $item['quantity'] ?? 0,
                'unit' => $item['unit'] ?? '',
                'rate' => $item['rate'] ?? 0,
                'amount' => $item['amount'] ?? 0,
            ]);
        }
    }

    /**
     * Calculate totals
     */
    protected function calculateTotals(array $data, array $items): array
    {
        $subtotal = 0;
        foreach ($items as $item) {
            $subtotal += floatval($item['amount'] ?? 0);
        }

        $data['subtotal'] = $subtotal;

        // Calculate GST
        $sgst = floatval($data['sgst_amount'] ?? 0);
        $cgst = floatval($data['cgst_amount'] ?? 0);
        $igst = floatval($data['igst_amount'] ?? 0);
        $roundUp = floatval($data['round_up'] ?? 0);

        $data['grand_total'] = $subtotal + $sgst + $cgst + $igst + $roundUp;

        // Convert to words
        $data['inr_in_words'] = numberToWords($data['grand_total']);

        return $data;
    }

    /**
     * Generate next sales order number
     */
    public function generateSalesOrderNumber(): string
    {
        $year = date('Y');
        $prefix = "SO/{$year}";
        return nextNumber($prefix, 'sales_orders', 'sales_order_no', 2);
    }

    /**
     * Update sales order status
     */
    public function updateStatus(int $id, string $status): SalesOrder
    {
        return $this->salesOrderRepository->updateStatus($id, $status);
    }

    /**
     * Get for DataTable
     */
    public function getForDataTable()
    {
        return $this->salesOrderRepository->getForDataTableWithRelations();
    }

    /**
     * Get sales orders without route card
     */
    public function getWithoutRouteCard(): Collection
    {
        return $this->salesOrderRepository->getWithoutRouteCard();
    }

    /**
     * Search sales orders
     */
    public function search(string $term): Collection
    {
        return $this->salesOrderRepository->search($term);
    }

    /**
     * Generate PDF
     */
    public function generatePdf(int $id, string $viewPath): \Illuminate\Http\Response
    {
        $salesOrder = $this->salesOrderRepository->with(['items', 'customer'])->find($id);

        $pdf = Pdf::loadView($viewPath, compact('salesOrder'));
        return $pdf->download("sales-order-{$salesOrder->sales_order_no}.pdf");
    }
}
