<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Booking;
use App\Models\BookingCategory;
use App\Models\PaperSize;
use App\Models\PaperType;
use App\Models\PaperBrand;
use App\Models\PaperGsm;
use App\Models\PrintType;
use App\Models\ColorType;
use App\Models\PrintMethod;
use App\Models\Lamination;
use App\Models\LaminationSide;
use App\Models\Binding;
use App\Models\Folding;
use App\Models\CornerType;
use App\Models\PaymentTerm;
use App\Models\DeliveryType;
use App\Models\JobPriority;
use App\Models\JobStatusMaster;
use App\Models\Customer;
use App\Models\PrintJob;
use App\Models\CarbonCopy;
use DB;

class BookingController extends Controller
{
    public function index(Request $request)
    {
        if ($request->ajax()) {
            $query = Booking::with('customer')->orderBy('id', 'desc');

            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }

            $data = $query->get();

            return datatables()->of($data)
                ->addIndexColumn()
                ->editColumn('booking_date', function ($row) {
                    return date('d-m-Y', strtotime($row->booking_date));
                })
                ->editColumn('customer_name', function ($row) {
                    return $row->customer?->name ?? $row->customer_name;
                })
                ->addColumn('advance', function ($row) {
                    return $row->payments()->sum('advance_amount');
                })
                ->addColumn('balance', function ($row) {
                    return $row->payments()->sum('balance_amount');
                })
                ->addColumn('action', function ($row) {
                    $showUrl = route('bookings.show', $row->id);
                    $editUrl = route('bookings.edit', $row->id);
                    return '<a href="'.$showUrl.'" class="btn btn-sm btn-info text-white"><i class="fas fa-eye"></i></a>
                            <a href="'.$editUrl.'" class="btn btn-sm btn-primary"><i class="fas fa-edit"></i></a>
                            <button class="btn btn-sm btn-danger delete-btn" data-id="'.$row->id.'"><i class="fas fa-trash"></i></button>';
                })
                ->rawColumns(['action'])
                ->make(true);
        }

        return view('bookings.index');
    }

    public function create()
    {
        $data = $this->masterData();
        $lastBooking = Booking::latest('id')->first();
        $nextId = $lastBooking ? $lastBooking->id + 1 : 1;
        $data['booking_no'] = 'BKG-' . date('Ym') . '-' . str_pad($nextId, 4, '0', STR_PAD_LEFT);

        return view('bookings.create', $data);
    }

    public function store(Request $request)
    {
        $request->validate([
            'booking_date' => 'required|date',
            'customer_id' => 'required|exists:customers,id',
            'category_id' => 'required|exists:booking_categories,id',
            'quantity' => 'required|integer|min:1',
            'grand_total' => 'required|numeric|min:0',
        ]);

        try {
            DB::beginTransaction();

            $customer = Customer::findOrFail($request->customer_id);

            $booking = Booking::create([
                'booking_no' => $request->booking_no,
                'booking_date' => $request->booking_date,
                'customer_id' => $customer->id,
                'customer_name' => $customer->name,
                'mobile' => $customer->mobile ?: '0000000000',
                'address' => $customer->address,
                'job_name' => $request->job_name,
                'grand_total' => $request->grand_total,
                'status' => 'Pending',
            ]);

            $booking->items()->create($request->only([
                'category_id', 'paper_size_id', 'custom_width', 'custom_height', 'custom_unit',
                'paper_type_id', 'paper_brand_id', 'paper_gsm_id', 'print_type_id', 'color_type_id',
                'print_method_id', 'lamination_id', 'lamination_side_id', 'corner_type_id', 'binding_id',
                'folding_id', 'quantity', 'extra_copies', 'waste_percentage', 'total_quantity',
                'carbon_copy', 'bill_binding',
            ]));

            if ($request->has('other_costs')) {
                foreach ($request->other_costs as $cost) {
                    if (!empty($cost['description']) && !empty($cost['amount'])) {
                        $booking->otherCosts()->create($cost);
                    }
                }
            }

            $booking->delivery()->create($request->only([
                'delivery_type_id', 'delivery_address', 'receiver_name', 'receiver_mobile',
            ]));

            $booking->payments()->create($request->only([
                'payment_term_id', 'advance_amount', 'balance_amount',
            ]));

            $booking->statusHistory()->create([
                'status_name' => 'Pending',
                'notes' => 'Quotation Created',
            ]);

            DB::commit();
            return redirect()->route('bookings.index')->with('success', 'Quotation booking created successfully.');
        } catch (\Exception $e) {
            DB::rollback();
            return back()->with('error', 'Error creating booking: ' . $e->getMessage())->withInput();
        }
    }

    public function show($id)
    {
        $booking = Booking::with([
            'items', 'otherCosts', 'delivery', 'payments', 'statusHistory',
            'priority', 'customer', 'printJob',
        ])->findOrFail($id);

        return view('bookings.show', compact('booking'));
    }

    public function edit($id)
    {
        $booking = Booking::with(['items', 'customer'])->findOrFail($id);
        $data = $this->masterData();
        $data['booking'] = $booking;

        return view('bookings.edit', $data);
    }

    public function update(Request $request, $id)
    {
        $request->validate([
            'booking_date' => 'required|date',
            'customer_id' => 'required|exists:customers,id',
            'category_id' => 'required|exists:booking_categories,id',
            'quantity' => 'required|integer|min:1',
            'grand_total' => 'required|numeric|min:0',
        ]);

        try {
            DB::beginTransaction();

            $booking = Booking::findOrFail($id);
            $customer = Customer::findOrFail($request->customer_id);

            $booking->update([
                'booking_date' => $request->booking_date,
                'customer_id' => $customer->id,
                'customer_name' => $customer->name,
                'mobile' => $customer->mobile ?: $booking->mobile,
                'address' => $customer->address,
                'job_name' => $request->job_name,
                'grand_total' => $request->grand_total,
            ]);

            if ($booking->items()->count() > 0) {
                $booking->items()->first()->update($request->only([
                    'category_id', 'paper_size_id', 'paper_gsm_id', 'print_type_id',
                    'lamination_id', 'lamination_side_id', 'quantity',
                    'carbon_copy', 'bill_binding',
                ]));
            }

            DB::commit();
            return redirect()->route('bookings.index')->with('success', 'Quotation booking updated successfully.');
        } catch (\Exception $e) {
            DB::rollback();
            return back()->with('error', 'Error updating booking: ' . $e->getMessage())->withInput();
        }
    }

    public function destroy($id)
    {
        $booking = Booking::findOrFail($id);
        $booking->delete();
        return response()->json(['success' => true, 'message' => 'Booking deleted successfully']);
    }

    public function updateStatus(Request $request, $id)
    {
        $request->validate([
            'status' => 'required|in:Pending,Confirmed',
        ]);

        try {
            DB::beginTransaction();
            $booking = Booking::with(['items', 'customer'])->findOrFail($id);
            $oldStatus = $booking->status;
            $booking->status = $request->status;
            $booking->save();

            $booking->statusHistory()->create([
                'status_name' => $request->status,
                'notes' => 'Status changed from List View',
            ]);

            if ($request->status === 'Confirmed' && $oldStatus !== 'Confirmed') {
                $this->createPrintJobFromBooking($booking);
            }

            DB::commit();
            return response()->json(['success' => true, 'message' => 'Status updated successfully']);
        } catch (\Exception $e) {
            DB::rollback();
            return response()->json(['success' => false, 'message' => 'Error updating status: '.$e->getMessage()], 500);
        }
    }

    protected function createPrintJobFromBooking(Booking $booking)
    {
        if ($booking->printJob) {
            return $booking->printJob;
        }

        $item = $booking->items->first();
        $customer = $booking->customer;
        $lastJob = PrintJob::latest('id')->first();
        $nextId = $lastJob ? $lastJob->id + 1 : 1;
        $jobNo = 'JOB-' . date('Ym') . '-' . str_pad($nextId, 4, '0', STR_PAD_LEFT);

        return PrintJob::create([
            'booking_id' => $booking->id,
            'job_no' => $jobNo,
            'booking_no' => $booking->booking_no,
            'booking_date' => $booking->booking_date,
            'customer_id' => $booking->customer_id,
            'customer_name' => $customer?->name ?? $booking->customer_name,
            'address' => $customer?->address ?? $booking->address,
            'mobile' => $customer?->mobile ?? $booking->mobile,
            'job_name' => $booking->job_name,
            'category_name' => $item ? BookingCategory::find($item->category_id)?->name : null,
            'paper_size' => $item ? PaperSize::find($item->paper_size_id)?->name : null,
            'paper_gsm' => $item ? PaperGsm::find($item->paper_gsm_id)?->name : null,
            'print_type' => $item ? PrintType::find($item->print_type_id)?->name : null,
            'lamination' => $item ? Lamination::find($item->lamination_id)?->name : null,
            'lamination_side' => $item ? LaminationSide::find($item->lamination_side_id)?->name : null,
            'carbon_copy' => $item?->carbon_copy,
            'bill_binding' => $item?->bill_binding,
            'quantity' => $item?->quantity ?? 0,
            'grand_total' => $booking->grand_total,
            'job_status' => 'DTP Approved',
        ]);
    }

    protected function masterData(): array
    {
        return [
            'categories' => BookingCategory::where('status', 1)->orderBy('sort_order')->get(),
            'paperSizes' => PaperSize::where('status', 1)->orderBy('sort_order')->get(),
            'paperTypes' => PaperType::where('status', 1)->orderBy('sort_order')->get(),
            'paperBrands' => PaperBrand::where('status', 1)->orderBy('sort_order')->get(),
            'paperGsms' => PaperGsm::where('status', 1)->orderBy('sort_order')->get(),
            'printTypes' => PrintType::where('status', 1)->orderBy('sort_order')->get(),
            'colorTypes' => ColorType::where('status', 1)->orderBy('sort_order')->get(),
            'printMethods' => PrintMethod::where('status', 1)->orderBy('sort_order')->get(),
            'laminations' => Lamination::where('status', 1)->orderBy('sort_order')->get(),
            'laminationSides' => LaminationSide::where('status', 1)->orderBy('sort_order')->get(),
            'bindings' => Binding::where('status', 1)->orderBy('sort_order')->get(),
            'foldings' => Folding::where('status', 1)->orderBy('sort_order')->get(),
            'cornerTypes' => CornerType::where('status', 1)->orderBy('sort_order')->get(),
            'paymentTerms' => PaymentTerm::where('status', 1)->orderBy('sort_order')->get(),
            'deliveryTypes' => DeliveryType::where('status', 1)->orderBy('sort_order')->get(),
            'jobPriorities' => JobPriority::where('status', 1)->orderBy('sort_order')->get(),
            'jobStatuses' => JobStatusMaster::where('status', 1)->orderBy('sort_order')->get(),
            'customers' => Customer::where('status', 1)->orderBy('name')->get(),
            'carbonCopies' => CarbonCopy::where('status', 1)->orderBy('sort_order')->get(),
        ];
    }
}
