<?php

namespace App\Http\Controllers;

use App\Models\SupplierDocumentHeader;
use App\Models\SupplierDocumentLine;
use App\Models\SupplierAccount;
use App\Models\PriceListingSetup;
use App\Models\GeneralLedger;
use App\Models\Warehouse;
use App\Models\Project;
use App\Models\Tax;
use App\Models\Currency;
use App\Models\Uom;
use App\Models\SupplierDocumentSetting;
use App\Models\CompanySettings;
use App\Models\WarehouseTransfer;
use App\Models\WarehouseTransferLine;
use App\Models\ItemWarehouse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Barryvdh\DomPDF\Facade\Pdf as PDF;
use Illuminate\Support\Str;

class SupplierDocumentController extends Controller
{
    public function create($type)
    {
        $themeColors = [
            'purchase_order'   => ['color' => '#4a6da7', 'light' => '#6a8bc7', 'dark' => '#2a4d87'],
            'goods_received'   => ['color' => '#28a745', 'light' => '#5cb85c', 'dark' => '#1e7e34'],
            'sales_invoice'    => ['color' => '#6f42c1', 'light' => '#9d7bd9', 'dark' => '#563d7c'],
            'returns_debit'    => ['color' => '#ff6b6b', 'light' => '#ff9b9b', 'dark' => '#e53b3b'],
            'credit_supplier'  => ['color' => '#17a2b8', 'light' => '#5bc0de', 'dark' => '#117a8b'],
        ];

        $theme = $themeColors[$type] ?? $themeColors['purchase_order'];

        SupplierDocumentSetting::firstOrCreate(
            ['document_type' => $type],
            ['prefix' => $this->getDefaultPrefix($type), 'start_number' => 1, 'pricing_type' => 'exclusive']
        );

        $settings        = SupplierDocumentSetting::where('document_type', $type)->first();
        $pricingType     = $settings->pricing_type ?? session('pricing_type', 'exclusive');
        $documentNumber  = $this->generateDocumentNumber($type, false);
        $uoms            = Uom::all();
        $UOM             = $uoms->first();

        return view('maintanance.suppliers.create_supplier', [
            'type'               => $type,
            'documentTitle'      => $this->getDocumentTitle($type),
            'suppliers'          => SupplierAccount::all(),
            'items'              => $this->getItems(),
            'accounts'           => GeneralLedger::with('subAccounts')->get(),
            'warehouses'         => Warehouse::all(),
            'projects'           => Project::all(),
            'taxes'              => Tax::all(),
            'currencies'         => Currency::all(),
            'uoms'               => $uoms,
            'UOM'                => $UOM,
            'documentNumber'     => $documentNumber,
            'showNegativeOption' => in_array($type, ['sales_invoice','returns_debit','credit_supplier']),
            'themeColor'         => $theme['color'],
            'themeLight'         => $theme['light'],
            'themeDark'          => $theme['dark'],
            'pricingType'        => $pricingType,
        ]);
    }

    private function getDocumentTitle($type)
    {
        $titles = [
            'purchase_order'   => 'Purchases Order',
            'goods_received'   => 'Goods Received Voucher',
            'sales_invoice'    => 'Supplier Invoice',
            'returns_debit'    => 'Return & Debit',
            'credit_supplier'  => 'Credit to Supplier',
        ];

        return $titles[$type] ?? 'Supplier Document';
    }

    private function getDefaultPrefix($type)
    {
        $prefixes = [
            'purchase_order'   => 'PO',
            'goods_received'   => 'GRV',
            'sales_invoice'    => 'SINV',
            'returns_debit'    => 'RDN',
            'credit_supplier'  => 'CS',
        ];

        return $prefixes[$type] ?? 'SD';
    }

   private function getItems()
    {
        $availableQuantities = SupplierDocumentLine::select('item_id', DB::raw('SUM(confirmed_quantity) as total_available'))
            ->whereHas('header', function($query) {
                $query->where('type', 'goods_received');
            })
            ->groupBy('item_id')
            ->pluck('total_available', 'item_id');

        return PriceListingSetup::with(['stockingUnit','warehouse','itemWarehouses'])
            ->get()
            ->map(function($item) use ($availableQuantities) {
                $availableFromGRV = $availableQuantities->get($item->id, 0);

                // Sum across all warehouses for this item
                $stockFromWarehouses = $item->itemWarehouses->sum('quantity');

                $available = $stockFromWarehouses;

                return [
                    'id'             => $item->id,
                    'code'           => $item->code,
                    'description1'   => $item->description1,
                    'description2'   => $item->description2,
                    'warehouse_id'   => $item->warehouse_id,
                    'warehouse_desc' => optional($item->warehouse)->description ?? '',
                    'uom'            => optional($item->stockingUnit)->code ?? '',
                    'cost'           => $item->cost,
                    'available'      => $available,
                ];
            });
    }


    private function generateDocumentNumber(string $type, bool $increment = true): string
    {
        return DB::transaction(function() use ($type, $increment) {
            $settings = SupplierDocumentSetting::where('document_type', $type)
                ->lockForUpdate()
                ->first();

            if (!$settings) {
                $settings = SupplierDocumentSetting::create([
                    'document_type' => $type,
                    'prefix'        => $this->getDefaultPrefix($type),
                    'start_number'  => 1,
                    'pricing_type'  => 'exclusive'
                ]);
            }

            $nextId = $settings->start_number;
            if ($increment) {
                $settings->start_number = $nextId + 1;
                $settings->save();
            }

            $prefix = $settings->prefix ?: $this->getDefaultPrefix($type);
            return $prefix . str_pad($nextId, 6, '0', STR_PAD_LEFT);
        });
    }

    public function store(Request $request, $type)
    {
        $request->validate([
            'supplier_account_id' => 'required|exists:supplier_accounts,id',
            'document_date'       => 'required|date',
            'lines'               => 'required|array|min:1',
        ]);

        $documentNumber = $this->generateDocumentNumber($type, true);

        $header = SupplierDocumentHeader::create([
            'type'                 => $type,
            'document_number'      => $documentNumber,
            'supplier_account_id'  => $request->supplier_account_id,
            'contact_person'       => $request->contact_person,
            'document_date'        => $request->document_date,
            'delivery_date'        => $request->delivery_date,
            'order_number'         => $request->order_number,
            'project_id'           => $request->project_id,
            'currency_code'        => $request->currency_code,
            'allow_negative'       => $request->has('allow_negative') ? 1 : 0,
            'status'               => 'draft',
            'exclusive_total'      => 0,
            'tax_amount'           => 0,
            'discount_total'       => 0,
            'inclusive_total'      => 0,
            'pricing_type'         => $request->pricing_type,
            'notes'                => $request->special_instructions,
            'addedby' => Auth::id() // ✅ track who did it
        ]);

        $exclTotal     = 0;
        $taxTotal      = 0;
        $discountTotal = 0;

        foreach ($request->lines as $line) {
            $taxRate      = Tax::find($line['tax_id'])->rate;
            $price        = $line['price'];
            $confirmedQty = $line['confirmed_quantity'] ?? $line['quantity'];

            if ($request->pricing_type === 'inclusive') {
                $priceExcl = $price / (1 + ($taxRate / 100));
                $unitTax   = $price - $priceExcl;
            } else {
                $priceExcl = $price;
                $unitTax   = 0;
            }

            $excl     = $confirmedQty * $priceExcl;
            $discount = $excl * ($line['discount_percent'] / 100);
            $taxable  = $excl - $discount;
            $tax      = $taxable * ($taxRate / 100);
            $total    = $taxable + $tax;

            $header->lines()->create([
                'module'             => $line['module'],
                'hs_code'            => $line['hs_code'] ?? null,
                'item_id'            => $line['item_id'] ?? null,
                'account_id'         => $line['account_id'] ?? null,
                'warehouse_id'       => $line['warehouse_id'] ?? null,
                'quantity'           => $line['quantity'],
                'confirmed_quantity' => $confirmedQty,
                'uom_id'             => $line['uom_id'] ?? null,
                'price'              => $price,
                'tax_id'             => $line['tax_id'],
                'tax_rate'           => $taxRate,
                'discount_percent'   => $line['discount_percent'] ?? 0,
                'line_tax'           => $request->pricing_type === 'inclusive'
                                         ? ($confirmedQty * $unitTax)
                                         : $tax,
                'line_total'         => $total,
                'description'        => $line['description'] ?? null,
            ]);

        // 🔥 Update itemwarehouse stock
        if (!empty($line['item_id']) && !empty($line['warehouse_id'])) {
            // decide whether to add or subtract
            $adjustment = ($type === 'returns_debit')
                ? -$confirmedQty   // subtract for returns
                : $confirmedQty;   // add for others

            ItemWarehouse::updateOrCreate(
                [
                    'item_id'      => $line['item_id'],
                    'warehouse_id' => $line['warehouse_id'],
                ],
                [
                    // increment or decrement based on type
                    'quantity' => \DB::raw('quantity + ' . $adjustment),
                ]
            );
        }

            $exclTotal     += $taxable;
            $taxTotal      += $tax;
            $discountTotal += $discount;
        }
        $header->update([
            'exclusive_total' => $exclTotal,
            'tax_amount'      => $taxTotal,
            'discount_total'  => $discountTotal,
            'inclusive_total' => $exclTotal + $taxTotal,
            'status'          => 'processed',
        ]);

        return $this->processDocument($header);
    }

    private function processDocument(SupplierDocumentHeader $document)
    {
        $pdf = PDF::loadView('documents.supplier.pdf', [
            'document'    => $document,
            'company'     => CompanySettings::first(),
            'pricingType' => $document->pricing_type,
        ]);

        return $pdf->download("{$document->document_number}.pdf");
    }

    public function deliveryNote(SupplierDocumentHeader $document)
    {
        $pdf = PDF::loadView('documents.supplier.delivery_note', [
            'document' => $document,
            'company'  => CompanySettings::first(),
        ]);

        return $pdf->download("DN-{$document->document_number}.pdf");
    }

    public function invoice(SupplierDocumentHeader $document)
    {
        return $this->processInvoice($document);
    }

    public function processInvoice(SupplierDocumentHeader $document)
    {
        $pdf = PDF::loadView('documents.supplier.pdf', [
            'document'    => $document,
            'company'     => CompanySettings::first(),
            'pricingType' => $document->pricing_type,
        ]);

        return $pdf->download("{$document->document_number}.pdf");
    }

    public function deliveryNotePreview(SupplierDocumentHeader $document)
    {
        return view('documents.supplier.delivery_note', [
            'document' => $document,
            'company'  => CompanySettings::first(),
            'preview'  => true,
        ]);
    }

    public function invoicePreview(SupplierDocumentHeader $document)
    {
        return view('documents.supplier.pdf', [
            'document'    => $document,
            'company'     => CompanySettings::first(),
            'pricingType' => $document->pricing_type,
            'preview'     => true,
        ]);
    }

    public function pdf(SupplierDocumentHeader $document)
    {
        return view('documents.supplier.pdf', [
            'document'    => $document,
            'company'     => CompanySettings::first(),
            'pricingType' => $document->pricing_type,
        ]);
    }

    public function updateDocumentSettings(Request $request)
    {
        $request->validate([
            'prefix'        => 'nullable|string|max:10',
            'start_number'  => 'nullable|integer|min:0',
            'pricing_type'  => 'nullable|in:exclusive,inclusive',
            'document_type' => 'required|string',
        ]);

        $settings = SupplierDocumentSetting::updateOrCreate(
            ['document_type' => $request->document_type],
            array_filter([
                'prefix'       => $request->prefix,
                'start_number' => $request->start_number,
                'pricing_type' => $request->pricing_type,
            ])
        );

        if ($request->pricing_type) {
            session(['pricing_type' => $request->pricing_type]);
        }

        return response()->json(['success' => true]);
    }
    // ---------- Warehouse Transfer Methods ----------

    public function warehouseTransfer()
    {
        $theme = [
            'color' => '#018ca3',
            'light' => '#3fb4c6',
            'dark'  => '#016a7c'
        ];

        $nextId     = WarehouseTransfer::max('id') + 1;
        $warehouses = Warehouse::all();
        $items      = $this->getItems();
        $uoms       = Uom::all();

        return view('maintanance.suppliers.warehouse_transfer', [
            'nextId'      => $nextId,
            'warehouses'  => $warehouses,
            'items'       => $items,
            'uoms'        => $uoms,
            'themeColor'  => $theme['color'],
            'themeLight'  => $theme['light'],
            'themeDark'   => $theme['dark'],
        ]);
    }

    /**
     * AJAX: return available qty for an item in a single warehouse.
     */

    public function getAvailableQuantity($itemId, $warehouseId)
    {
        // 1. original stock in that warehouse
        $original = PriceListingSetup::where('id', $itemId)
            ->where('warehouse_id', $warehouseId)
            ->value('original_quantity') ?? 0;

        // 2. all GRV receipts into this warehouse for this item
        $received = SupplierDocumentLine::where('item_id', $itemId)
            ->where('warehouse_id', $warehouseId)
            ->whereHas('header', fn($q) => $q->where('type', 'goods_received')->where('status', 'processed'))
            ->sum('confirmed_quantity');

        // 3. transfers in/out for this warehouse
        $transIn  = WarehouseTransferLine::where('item_id', $itemId)
            ->where('to_warehouse_id', $warehouseId)
            ->sum('quantity');
        $transOut = WarehouseTransferLine::where('item_id', $itemId)
            ->where('from_warehouse_id', $warehouseId)
            ->sum('quantity');

        $available = $original + $received + $transIn - $transOut;

        return response()->json(['available' => $available]);
    }

  private function calculateAvailableQuantity($itemId, $warehouseId)
{
    // Quantity originally entered into stock (per warehouse and item)
    $originalQty = PriceListingSetup::where('item_id', $itemId)
        ->where('warehouse_id', $warehouseId)
        ->sum('original_quantity');

    // Goods received from suppliers
    $receivedQty = SupplierDocumentLine::where('item_id', $itemId)
        ->where('warehouse_id', $warehouseId)
        ->whereHas('header', function($query) {
            $query->where('type', 'goods_received');
        })
        ->sum('confirmed_quantity');

    // Issued out (sold or returned)
    $issuedQty = SupplierDocumentLine::where('item_id', $itemId)
        ->where('warehouse_id', $warehouseId)
        ->whereHas('header', function($query) {
            $query->whereIn('type', ['sales_invoice', 'returns_debit']);
        })
        ->sum('confirmed_quantity');

    // Transfers out from this warehouse
    $transferredOut = WarehouseTransferLine::where('item_id', $itemId)
        ->where('from_warehouse_id', $warehouseId)
        ->sum('quantity');

    // Transfers into this warehouse
    $transferredIn = WarehouseTransferLine::where('item_id', $itemId)
        ->where('to_warehouse_id', $warehouseId)
        ->sum('quantity');

    $available = $originalQty + $receivedQty + $transferredIn - $issuedQty - $transferredOut;

    return $available;
}

public function getItemAvailability(Request $request)
{
    $itemId = $request->input('item_id');
    $warehouseId = $request->input('warehouse_id');

    $available = $this->calculateAvailableQuantity($itemId, $warehouseId);

    return response()->json([
        'available_quantity' => $available
    ]);
}


   public function storeWarehouseTransfer(Request $request)
{
    $request->validate([
        'transfer_date'       => 'required|date',
        'from_warehouse_id'   => 'required|exists:warehouses,id',
        'to_warehouse_id'     => 'required|exists:warehouses,id',
        'lines'               => 'required|array|min:1',
    ]);

    DB::beginTransaction();

    try {
        // Create transfer header
        $transfer = WarehouseTransfer::create([
            'document_number'    => $request->document_number,
            'transfer_date'      => $request->transfer_date,
            'from_warehouse_id'  => $request->from_warehouse_id,
            'to_warehouse_id'    => $request->to_warehouse_id,
            'reference_number'   => $request->reference_number,
            'notes'              => $request->notes,
            'status'             => 'completed',
        ]);

        foreach ($request->lines as $line) {
            // Create transfer line
            WarehouseTransferLine::create([
                'transfer_id' => $transfer->id,
                'item_id'     => $line['item_id'],
                'reference'   => $line['reference'] ?? '',
                'uom_id'      => $line['uom_id'],
                'quantity'    => $line['quantity'],
            ]);

            // 1. Subtract from the FROM warehouse
            DB::table('itemwarehouse')
                ->where('item_id', $line['item_id'])
                ->where('warehouse_id', $request->from_warehouse_id)
                ->decrement('quantity', $line['quantity']);

            // 2. Add to the TO warehouse
            $affected = DB::table('itemwarehouse')
                ->where('item_id', $line['item_id'])
                ->where('warehouse_id', $request->to_warehouse_id)
                ->increment('quantity', $line['quantity']);

            // 3. If TO warehouse row doesn’t exist, insert new row
            if ($affected === 0) {
                DB::table('itemwarehouse')->insert([
                    'item_id'      => $line['item_id'],
                    'warehouse_id' => $request->to_warehouse_id,
                    'quantity'     => $line['quantity'],
                    'created_at'   => now(),
                    'updated_at'   => now(),
                ]);
            }
        }

        DB::commit();

        return redirect()->route('warehouse.transfer.show', $transfer->id)
            ->with('success', 'Warehouse transfer completed successfully!');
    } catch (\Exception $e) {
        DB::rollBack();
        return back()->withInput()->with('error', 'Error processing transfer: ' . $e->getMessage());
    }
}

}
