<?php

namespace App\Services;

use Illuminate\Support\Facades\DB;

/**
 * Document Number Service
 *
 * Centralized service for generating sequential document numbers
 * across all modules. Uses configuration from config/document_prefixes.php
 * to eliminate hardcoded prefix values.
 */
class DocumentNumberService
{
    protected int $padding;
    protected string $separator;
    protected bool $includeYear;
    protected string $yearFormat;

    public function __construct()
    {
        $this->padding = config('document_prefixes.number_padding', 4);
        $this->separator = config('document_prefixes.separator', '/');
        $this->includeYear = config('document_prefixes.include_year', true);
        $this->yearFormat = config('document_prefixes.year_format', 'Y');
    }

    // ──────────────────────────────────────────────────────────────────────────
    // GENERIC NUMBER GENERATION
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate next sequential number for any document type
     * Uses DB locking to prevent race conditions under concurrent requests
     */
    public function generate(string $prefix, string $table, string $column, int $prefixParts = 2): string
    {
        return DB::transaction(function () use ($prefix, $table, $column, $prefixParts) {
            $lastRecord = DB::table($table)
                ->lockForUpdate()
                ->orderByDesc($column)
                ->first([$column]);

            if (!$lastRecord) {
                return $prefix . $this->separator . $this->padNumber(1);
            }

            $lastNumber = $lastRecord->$column;
            $parts = explode($this->separator, $lastNumber);

            if (count($parts) > $prefixParts) {
                $number = (int) end($parts) + 1;
            } else {
                $number = 1;
            }

            return $prefix . $this->separator . $this->padNumber($number);
        });
    }

    /**
     * Generate number with year prefix
     */
    public function generateWithYear(string $prefix, string $table, string $column, int $prefixParts = 2): string
    {
        $year = date($this->yearFormat);
        $fullPrefix = $prefix . $this->separator . $year;

        return $this->generate($fullPrefix, $table, $column, $prefixParts + 1);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // SALES MODULE
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate RFQ number
     */
    public function generateRfqNumber(bool $isSuperAdmin = false): string
    {
        $prefix = $isSuperAdmin
            ? config('document_prefixes.rfq.sales')
            : config('document_prefixes.rfq.legacy');

        return $this->generate($prefix, 'rfqs', 'rfq_no', 2);
    }

    /**
     * Generate Quotation number
     */
    public function generateQuotationNumber(): string
    {
        $prefix = config('document_prefixes.quotation.sales');
        return $this->generate($prefix, 'quotations', 'quotation_no', 2);
    }

    /**
     * Generate Sales Order number
     */
    public function generateSalesOrderNumber(): string
    {
        $prefix = config('document_prefixes.sales_order');
        return $this->generate($prefix, 'sales_orders', 'sales_order_no', 1);
    }

    /**
     * Generate Invoice number
     */
    public function generateInvoiceNumber(): string
    {
        $prefix = config('document_prefixes.invoice.sales');
        return $this->generate($prefix, 'tax_invoices', 'invoice_no', 2);
    }

    /**
     * Generate Debit Note number
     */
    public function generateDebitNoteNumber(): string
    {
        $prefix = config('document_prefixes.debit_note');
        return $this->generate($prefix, 'debit_notes', 'debit_note_no', 1);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // PURCHASE MODULE
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate Purchase RFQ number
     */
    public function generatePurchaseRfqNumber(): string
    {
        $prefix = config('document_prefixes.purchase_rfq');
        return $this->generateWithYear($prefix, 'purchase_rfqs', 'rfq_no', 1);
    }

    /**
     * Generate Purchase Quotation number
     */
    public function generatePurchaseQuotationNumber(): string
    {
        $prefix = config('document_prefixes.purchase_quotation.new');
        return $this->generate($prefix, 'purchase_quotations', 'quotation_no', 2);
    }

    /**
     * Generate Purchase Order number
     */
    public function generatePurchaseOrderNumber(): string
    {
        $prefix = config('document_prefixes.purchase_order.new');
        return $this->generate($prefix, 'purchase_orders', 'purchase_order_no', 1);
    }

    /**
     * Generate Purchase Invoice number
     */
    public function generatePurchaseInvoiceNumber(): string
    {
        $prefix = config('document_prefixes.purchase_invoice');
        return $this->generate($prefix, 'purchasesv1', 'purchase_no', 2);
    }

    /**
     * Generate GRN number
     */
    public function generateGrnNumber(): string
    {
        $prefix = config('document_prefixes.grn.new');
        return $this->generate($prefix, 'grns', 'grn_no', 1);
    }

    /**
     * Generate Credit Note number
     */
    public function generateCreditNoteNumber(): string
    {
        $prefix = config('document_prefixes.credit_note');
        return $this->generate($prefix, 'credit_notes', 'credit_note_no', 1);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // MANUFACTURING MODULE
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate Route Card number
     */
    public function generateRouteCardNumber(): string
    {
        $prefix = config('document_prefixes.route_card.new');
        return $this->generate($prefix, 'route_cards', 'route_no', 1);
    }

    /**
     * Generate SKU code
     */
    public function generateSkuCode(): string
    {
        $prefix = config('document_prefixes.sku');
        return $this->generate($prefix, 'sku_masters', 'sku_code', 0);
    }

    /**
     * Generate Quality Control number
     */
    public function generateQcNumber(): string
    {
        $prefix = config('document_prefixes.quality_control');
        return $this->generateWithYear($prefix, 'quality_controls', 'qc_no', 1);
    }

    /**
     * Generate QC Approval number
     */
    public function generateQcApprovalNumber(): string
    {
        $prefix = config('document_prefixes.qc_approval');
        return $this->generateWithYear($prefix, 'qc_approvals', 'approval_no', 1);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // INVENTORY MODULE
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate Stock Item code
     */
    public function generateStockItemCode(): string
    {
        $prefix = config('document_prefixes.stock_item');
        return $this->generate($prefix, 'stock_items', 'item_code', 0);
    }

    /**
     * Generate Raw Material code
     */
    public function generateRawMaterialCode(): string
    {
        $prefix = config('document_prefixes.raw_material');
        return $this->generate($prefix, 'raw_materials', 'code', 0);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // EMPLOYEE MODULE
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate Employee ID
     */
    public function generateEmployeeId(): string
    {
        $prefix = config('document_prefixes.employee');
        return $this->generate($prefix, 'employee_details', 'employee_id', 0);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // MASTER DATA
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Generate Machine code
     */
    public function generateMachineCode(): string
    {
        $prefix = config('document_prefixes.machine');
        return $this->generate($prefix, 'machines', 'machine_code', 0);
    }

    // ──────────────────────────────────────────────────────────────────────────
    // HELPERS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Pad number with leading zeros
     */
    protected function padNumber(int $number): string
    {
        return str_pad((string) $number, $this->padding, '0', STR_PAD_LEFT);
    }

    /**
     * Extract number from document string
     */
    public function extractNumber(string $documentNumber): int
    {
        $parts = explode($this->separator, $documentNumber);
        return (int) end($parts);
    }

    /**
     * Get prefix for document type
     */
    public function getPrefix(string $type, ?string $variant = null): string
    {
        $config = config("document_prefixes.{$type}");

        if (is_array($config) && $variant) {
            return $config[$variant] ?? $config[array_key_first($config)];
        }

        return is_array($config) ? $config[array_key_first($config)] : $config;
    }
}
