<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

use App\Models\SalesDamage;
use App\Models\StockBatch;
use App\Events\StockUpdated;
use Illuminate\Support\Facades\DB;

class SalesDamageController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $query = SalesDamage::with(['batch.brand', 'batch.size', 'batch.subSize']);

        if ($request->has('from_date') && $request->has('to_date')) {
            $query->whereBetween('created_at', [$request->from_date . ' 00:00:00', $request->to_date . ' 23:59:59']);
        }

        if ($request->has('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('batch_no', 'like', "%{$search}%")
                    ->orWhere('damage_no', 'like', "%{$search}%");
            });
        }

        // Relational Filters via Batch
        if ($request->has('brand_id') && $request->brand_id !== 'ALL') {
            $query->whereHas('batch', function ($q) use ($request) {
                $q->where('brand_id', $request->brand_id);
            });
        }
        if ($request->has('size_id') && $request->size_id !== 'ALL') {
            $query->whereHas('batch', function ($q) use ($request) {
                $q->where('size_id', $request->size_id);
            });
        }
        if ($request->has('sub_size_id') && $request->sub_size_id !== 'ALL') {
            $query->whereHas('batch', function ($q) use ($request) {
                $q->where('sub_size_id', $request->sub_size_id);
            });
        }

        return $query->orderBy('id', 'desc')->paginate($request->per_page ?? 10);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        if ($request->user()->role !== 'ADMIN') {
            return response()->json(['error' => 'Unauthorized. Only admins can log damages.'], 403);
        }

        $data = $request->validate([
            'items' => 'required|array|min:1',
            'items.*.batch_id' => 'required|exists:stock_batches,id',
            'items.*.quantity_pieces' => 'required|numeric|min:1',
            'items.*.weight_kg' => 'nullable|numeric|min:0',
            'items.*.reason' => 'nullable|string',
        ]);

        try {
            return DB::transaction(function () use ($data) {
                // Generate Damage No: GDN-{YY}{YY+1}-{seq}
                // Single GDN for the whole request
                $date = now();
                $year = $date->year;
                $month = $date->month;

                if ($month >= 4) {
                    $fyStart = $year;
                    $fyEnd = $year + 1;
                } else {
                    $fyStart = $year - 1;
                    $fyEnd = $year;
                }
                $shortStart = substr($fyStart, -2);
                $shortEnd = substr($fyEnd, -2);
                $prefix = "GDN-{$shortStart}{$shortEnd}-";

                $latestDamage = SalesDamage::where('damage_no', 'like', "{$prefix}%")
                    ->orderBy('id', 'desc')
                    ->first();

                $nextSeq = 1;
                if ($latestDamage) {
                    $parts = explode('-', $latestDamage->damage_no);
                    $seqPart = end($parts);
                    $nextSeq = intval($seqPart) + 1;
                }
                $damageNo = $prefix . str_pad($nextSeq, 3, '0', STR_PAD_LEFT);

                $createdDamages = [];

                foreach ($data['items'] as $itemData) {
                    $batch = StockBatch::lockForUpdate()->findOrFail($itemData['batch_id']);

                    if (!empty($itemData['weight_kg']) && $batch->available_weight_kg < $itemData['weight_kg']) {
                        throw new \Exception("Insufficient stock to mark as damaged for Batch {$batch->batch_no}.");
                    }
                    if ($batch->available_pieces < $itemData['quantity_pieces']) {
                        throw new \Exception("Insufficient pieces to mark as damaged for Batch {$batch->batch_no}.");
                    }

                    // Create Damage Record
                    $damage = SalesDamage::create([
                        'damage_no' => $damageNo, // Same GDN for all items in this request
                        'batch_id' => $batch->id,
                        'batch_no' => $batch->batch_no,
                        'quantity_pieces' => $itemData['quantity_pieces'],
                        'weight_kg' => $itemData['weight_kg'] ?? 0,
                        'reason' => $itemData['reason'] ?? null,
                    ]);

                    $createdDamages[] = $damage;

                    // Deduct from Stock
                    $batch->available_pieces -= $itemData['quantity_pieces'];

                    if (!empty($itemData['weight_kg']) && $itemData['weight_kg'] > 0) {
                        $batch->available_weight_kg -= $itemData['weight_kg'];
                    }

                    if (($batch->available_pieces !== null && $batch->available_pieces <= 0) || ($batch->available_weight_kg <= 0.1 && $batch->available_pieces === null)) {
                        $batch->status = 'CLOSED';
                        if ($batch->available_weight_kg < 0)
                            $batch->available_weight_kg = 0;
                    }
                    $batch->save();

                    StockUpdated::dispatch($batch);
                }

                return response()->json($createdDamages, 201);
            });
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, $id)
    {
        if ($request->user()->role !== 'ADMIN') {
            return response()->json(['error' => 'Unauthorized. Only admins can update damages.'], 403);
        }

        $data = $request->validate([
            'quantity_pieces' => 'required|numeric|min:0',
            'weight_kg' => 'nullable|numeric|min:0',
            'reason' => 'nullable|string',
        ]);

        try {
            return DB::transaction(function () use ($data, $id) {
                $damage = SalesDamage::findOrFail($id);

                if ($damage->status === 'VOID') {
                    throw new \Exception("Cannot update a VOID damage record.");
                }

                $batch = StockBatch::lockForUpdate()->findOrFail($damage->batch_id);

                // 1. Revert Previous Deduction (Add back stock)
                $batch->available_pieces += $damage->quantity_pieces;
                if (!empty($damage->weight_kg) && $damage->weight_kg > 0) {
                    $batch->available_weight_kg += $damage->weight_kg;
                }

                // 2. Validate New Request (Check if enough stock exists now)
                if (!empty($data['weight_kg']) && $batch->available_weight_kg < $data['weight_kg']) {
                    throw new \Exception("Insufficient stock to mark as damaged.");
                }

                // 3. Apply New Deduction
                $batch->available_pieces -= $data['quantity_pieces'];
                if (!empty($data['weight_kg']) && $data['weight_kg'] > 0) {
                    $batch->available_weight_kg -= $data['weight_kg'];
                }

                if (($batch->available_pieces !== null && $batch->available_pieces <= 0) || ($batch->available_weight_kg <= 0.1 && $batch->available_pieces === null)) {
                    $batch->status = 'CLOSED';
                    if ($batch->available_weight_kg < 0)
                        $batch->available_weight_kg = 0;
                } else {
                    $batch->status = 'ACTIVE';
                }
                $batch->save();

                // Update Damage Record
                $damage->quantity_pieces = $data['quantity_pieces'];
                $damage->weight_kg = $data['weight_kg'] ?? 0;
                $damage->reason = $data['reason'];
                $damage->save();

                StockUpdated::dispatch($batch);

                return response()->json($damage);
            });
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }

    /**
     * Void the specified damage record.
     */
    public function void(Request $request, $id)
    {
        if ($request->user()->role !== 'ADMIN') {
            return response()->json(['error' => 'Unauthorized. Only admins can void damages.'], 403);
        }

        try {
            return DB::transaction(function () use ($id) {
                $damage = SalesDamage::findOrFail($id);

                if ($damage->status === 'VOID') {
                    return response()->json(['message' => 'Damage record is already voided.']);
                }

                $batch = StockBatch::lockForUpdate()->findOrFail($damage->batch_id);

                // 1. Revert Deduction (Add back stock)
                $batch->available_pieces += $damage->quantity_pieces;
                if (!empty($damage->weight_kg) && $damage->weight_kg > 0) {
                    $batch->available_weight_kg += $damage->weight_kg;
                }

                // If batch was closed, reopen it
                if ($batch->status === 'CLOSED') {
                    $batch->status = 'ACTIVE';
                }
                $batch->save();

                // 2. Mark as Void
                $damage->status = 'VOID';
                $damage->save();

                StockUpdated::dispatch($batch);

                return response()->json($damage);
            });
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}
