<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Models\DebitNote;
use App\Models\Product;
use App\Models\Purchase;
use App\Models\Supplier;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class DebitNoteController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request): View
    {
        $perPage = $request->get('per_page', 10);
        $search = $request->get('search', '');

        $query = DebitNote::with(['supplier', 'company', 'purchase', 'creator']);

        if (! empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('debit_note_number', 'like', "%{$search}%")
                    ->orWhereHas('supplier', function ($supplierQuery) use ($search) {
                        $supplierQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                    })
                    ->orWhereHas('purchase', function ($purchaseQuery) use ($search) {
                        $purchaseQuery->where('purchase_number', 'like', "%{$search}%");
                    });
            });
        }

        $debitNotes = $query->orderBy('created_at', 'desc')->paginate($perPage);

        return view('admin.debit-notes.index', [
            'debitNotes' => $debitNotes,
            'perPage' => $perPage,
            'search' => $search,
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create(): View
    {
        $nextDebitNoteNumber = DebitNote::generateDebitNoteNumber();
        $companySettings = \App\Models\CompanySetting::getSettings();
        $localizationSettings = \App\Models\LocalizationSetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->orderBy('name')->get();
        $defaultCurrency = $localizationSettings->default_currency ?? 'USD';
        $defaultCurrencyModel = $currencies->where('code', $defaultCurrency)->first() ?? \App\Models\Currency::getDefault();

        return view('admin.debit-notes.create', [
            'nextDebitNoteNumber' => $nextDebitNoteNumber,
            'companySettings' => $companySettings,
            'currencies' => $currencies,
            'defaultCurrency' => $defaultCurrency,
            'defaultCurrencyModel' => $defaultCurrencyModel,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request): RedirectResponse
    {
        if (! $request->filled('company_id')) {
            $request->merge(['company_id' => null]);
        }

        $validated = $request->validate([
            'debit_note_number' => 'required|string|unique:debit_notes,debit_note_number',
            'debit_note_date' => 'required|date',
            'order_date' => 'nullable|date',
            'status' => 'required|in:draft,pending,approved,rejected,completed',
            'purchase_id' => 'nullable|exists:purchases,id',
            'company_id' => 'nullable|exists:companies,id',
            'supplier_id' => 'required|exists:suppliers,id',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'nullable|exists:products,id',
            'items.*.product_name' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.rate' => 'required|numeric|min:0',
            'items.*.discount' => 'nullable|numeric|min:0',
            'items.*.tax' => 'nullable|numeric|min:0',
            'items.*.unit' => 'nullable|string',
            'payment_method' => 'nullable|string',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'signature_type' => 'nullable|in:manual,esignature',
            'signature_id' => 'nullable|exists:signatures,id',
        ]);

        $companyId = $validated['company_id'] ?? null;
        if ($companyId === null) {
            $companyId = $this->resolveCompanyIdFromSettings();
        }
        if ($companyId === null) {
            return back()
                ->withInput()
                ->withErrors([
                    'company_id' => 'Please select a company in Bill From, or add an active company that matches your company settings.',
                ]);
        }

        try {
            DB::beginTransaction();

            // Calculate totals
            $amount = 0;
            $totalTax = 0;
            $totalDiscount = 0;

            foreach ($validated['items'] as $item) {
                $itemSubtotal = $item['quantity'] * $item['rate'];
                $itemDiscount = $item['discount'] ?? 0;
                $itemTax = ($itemSubtotal - $itemDiscount) * (($item['tax'] ?? 0) / 100);

                $amount += $itemSubtotal;
                $totalDiscount += $itemDiscount;
                $totalTax += $itemTax;
            }

            $total = $amount - $totalDiscount + $totalTax;

            // Create debit note
            $debitNote = DebitNote::create([
                'debit_note_number' => $validated['debit_note_number'],
                'debit_note_date' => $validated['debit_note_date'],
                'order_date' => $validated['order_date'] ?? null,
                'status' => $validated['status'],
                'purchase_id' => $validated['purchase_id'] ?? null,
                'company_id' => $companyId,
                'supplier_id' => $validated['supplier_id'],
                'amount' => $amount,
                'tax_amount' => $totalTax,
                'discount_amount' => $totalDiscount,
                'total' => $total,
                'payment_method' => $validated['payment_method'] ?? 'cash',
                'notes' => $validated['notes'] ?? null,
                'terms' => $validated['terms'] ?? null,
                'signature_type' => $validated['signature_type'] ?? 'manual',
                'signature_id' => $validated['signature_id'] ?? null,
                'created_by' => Auth::id(),
            ]);

            // Create items
            foreach ($validated['items'] as $index => $item) {
                $itemSubtotal = $item['quantity'] * $item['rate'];
                $itemDiscount = $item['discount'] ?? 0;
                $itemTax = ($itemSubtotal - $itemDiscount) * (($item['tax'] ?? 0) / 100);
                $itemAmount = $itemSubtotal - $itemDiscount + $itemTax;

                $debitNote->items()->create([
                    'product_id' => $item['product_id'] ?? null,
                    'description' => $item['product_name'],
                    'unit' => $item['unit'] ?? null,
                    'quantity' => $item['quantity'],
                    'rate' => $item['rate'],
                    'discount' => $itemDiscount,
                    'tax_rate' => $item['tax'] ?? 0,
                    'tax_amount' => $itemTax,
                    'amount' => $itemAmount,
                    'sort_order' => $index,
                ]);
            }

            DB::commit();

            return redirect()->route('admin.debit-notes.index')
                ->with('success', 'Debit note created successfully');
        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withInput()
                ->withErrors(['error' => 'Failed to create debit note: '.$e->getMessage()]);
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(DebitNote $debitNote): View
    {
        $debitNote->load(['supplier', 'company', 'purchase', 'items', 'creator', 'signature']);

        return view('admin.debit-notes.show', [
            'debitNote' => $debitNote,
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(DebitNote $debitNote): View
    {
        $debitNote->load(['items', 'company', 'supplier', 'purchase', 'signature']);
        $companySettings = \App\Models\CompanySetting::getSettings();
        $localizationSettings = \App\Models\LocalizationSetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->orderBy('name')->get();
        $defaultCurrency = $localizationSettings->default_currency ?? 'USD';
        $defaultCurrencyModel = $currencies->where('code', $defaultCurrency)->first() ?? \App\Models\Currency::getDefault();

        return view('admin.debit-notes.create', [
            'debitNote' => $debitNote,
            'nextDebitNoteNumber' => $debitNote->debit_note_number,
            'companySettings' => $companySettings,
            'currencies' => $currencies,
            'defaultCurrency' => $defaultCurrency,
            'defaultCurrencyModel' => $defaultCurrencyModel,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, DebitNote $debitNote): RedirectResponse
    {
        if (! $request->filled('company_id')) {
            $request->merge(['company_id' => null]);
        }

        $validated = $request->validate([
            'debit_note_number' => [
                'required',
                'string',
                Rule::unique('debit_notes', 'debit_note_number')->ignore($debitNote->id),
            ],
            'debit_note_date' => 'required|date',
            'order_date' => 'nullable|date',
            'status' => 'required|in:draft,pending,approved,rejected,completed',
            'purchase_id' => 'nullable|exists:purchases,id',
            'company_id' => 'nullable|exists:companies,id',
            'supplier_id' => 'required|exists:suppliers,id',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'nullable|exists:products,id',
            'items.*.product_name' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.rate' => 'required|numeric|min:0',
            'items.*.discount' => 'nullable|numeric|min:0',
            'items.*.tax' => 'nullable|numeric|min:0',
            'items.*.unit' => 'nullable|string',
            'payment_method' => 'nullable|string',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'signature_type' => 'nullable|in:manual,esignature',
            'signature_id' => 'nullable|exists:signatures,id',
        ]);

        $companyId = $validated['company_id'] ?? null;
        if ($companyId === null) {
            $companyId = $this->resolveCompanyIdFromSettings();
        }
        if ($companyId === null) {
            return back()
                ->withInput()
                ->withErrors([
                    'company_id' => 'Please select a company in Bill From, or add an active company that matches your company settings.',
                ]);
        }

        try {
            DB::beginTransaction();

            $amount = 0;
            $totalTax = 0;
            $totalDiscount = 0;

            foreach ($validated['items'] as $item) {
                $itemSubtotal = $item['quantity'] * $item['rate'];
                $itemDiscount = $item['discount'] ?? 0;
                $itemTax = ($itemSubtotal - $itemDiscount) * (($item['tax'] ?? 0) / 100);

                $amount += $itemSubtotal;
                $totalDiscount += $itemDiscount;
                $totalTax += $itemTax;
            }

            $total = $amount - $totalDiscount + $totalTax;

            $debitNote->update([
                'debit_note_number' => $validated['debit_note_number'],
                'debit_note_date' => $validated['debit_note_date'],
                'order_date' => $validated['order_date'] ?? null,
                'status' => $validated['status'],
                'purchase_id' => $validated['purchase_id'] ?? null,
                'company_id' => $companyId,
                'supplier_id' => $validated['supplier_id'],
                'amount' => $amount,
                'tax_amount' => $totalTax,
                'discount_amount' => $totalDiscount,
                'total' => $total,
                'payment_method' => $validated['payment_method'] ?? 'cash',
                'notes' => $validated['notes'] ?? null,
                'terms' => $validated['terms'] ?? null,
                'signature_type' => $validated['signature_type'] ?? 'manual',
                'signature_id' => $validated['signature_id'] ?? null,
            ]);

            $debitNote->items()->delete();

            foreach ($validated['items'] as $index => $item) {
                $itemSubtotal = $item['quantity'] * $item['rate'];
                $itemDiscount = $item['discount'] ?? 0;
                $itemTax = ($itemSubtotal - $itemDiscount) * (($item['tax'] ?? 0) / 100);
                $itemAmount = $itemSubtotal - $itemDiscount + $itemTax;

                $debitNote->items()->create([
                    'product_id' => $item['product_id'] ?? null,
                    'description' => $item['product_name'],
                    'unit' => $item['unit'] ?? null,
                    'quantity' => $item['quantity'],
                    'rate' => $item['rate'],
                    'discount' => $itemDiscount,
                    'tax_rate' => $item['tax'] ?? 0,
                    'tax_amount' => $itemTax,
                    'amount' => $itemAmount,
                    'sort_order' => $index,
                ]);
            }

            DB::commit();

            return redirect()->route('admin.debit-notes.index')
                ->with('success', 'Debit note updated successfully');
        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withInput()
                ->withErrors(['error' => 'Failed to update debit note: '.$e->getMessage()]);
        }
    }

    /**
     * API: Get purchases for dropdown (AJAX)
     */
    public function getPurchases(Request $request): JsonResponse
    {
        try {
            $query = Purchase::with(['supplier']);

            $search = $request->get('search', '');
            if (! empty($search)) {
                $query->where(function ($q) use ($search) {
                    $q->where('purchase_number', 'like', "%{$search}%")
                        ->orWhereHas('supplier', function ($sq) use ($search) {
                            $sq->where('name', 'like', "%{$search}%");
                        });
                });
            }

            $purchases = $query->orderBy('purchase_date', 'desc')->limit(50)->get();

            return response()->json([
                'success' => true,
                'purchases' => $purchases->map(function ($purchase) {
                    return [
                        'id' => $purchase->id,
                        'purchase_number' => $purchase->purchase_number,
                        'purchase_date' => $purchase->purchase_date->format('Y-m-d'),
                        'supplier_name' => $purchase->supplier ? $purchase->supplier->name : 'N/A',
                        'total' => $purchase->total,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching purchases: '.$e->getMessage(),
                'purchases' => [],
            ], 500);
        }
    }

    /**
     * API: Get companies for dropdown (AJAX)
     */
    public function getCompanies(Request $request): JsonResponse
    {
        try {
            $query = Company::where('is_active', true);

            $search = $request->get('search', '');
            if (! empty($search)) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                });
            }

            $companies = $query->orderBy('name', 'asc')->limit(50)->get();

            return response()->json([
                'success' => true,
                'companies' => $companies->map(function ($company) {
                    return [
                        'id' => $company->id,
                        'name' => $company->name,
                        'email' => $company->email ?? '',
                        'phone' => $company->phone ?? '',
                        'address' => $company->address ?? '',
                        'city' => $company->city ?? '',
                        'state' => $company->state ?? '',
                        'zip' => $company->zip ?? '',
                        'country' => $company->country ?? '',
                        'logo' => $company->logo_url,
                        'logo_path' => $company->logo,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching companies: '.$e->getMessage(),
                'companies' => [],
            ], 500);
        }
    }

    /**
     * API: Get suppliers for dropdown (AJAX)
     */
    public function getSuppliers(Request $request): JsonResponse
    {
        try {
            $query = Supplier::where('is_active', true);

            $search = $request->get('search', '');
            if (! empty($search)) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                });
            }

            $suppliers = $query->orderBy('name', 'asc')->limit(50)->get();

            return response()->json([
                'success' => true,
                'suppliers' => $suppliers->map(function ($supplier) {
                    return [
                        'id' => $supplier->id,
                        'name' => $supplier->name,
                        'email' => $supplier->email ?? '',
                        'phone' => $supplier->phone ?? '',
                        'address' => $supplier->address ?? '',
                        'city' => $supplier->city ?? '',
                        'state' => $supplier->state ?? '',
                        'zip' => $supplier->zip ?? '',
                        'country' => $supplier->country ?? '',
                        'image' => $supplier->image_url,
                        'image_path' => $supplier->image,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching suppliers: '.$e->getMessage(),
                'suppliers' => [],
            ], 500);
        }
    }

    /**
     * API: Get products for dropdown (AJAX)
     */
    public function getProducts(Request $request): JsonResponse
    {
        try {
            $query = Product::where('is_active', true);

            $search = $request->get('search', '');
            if (! empty($search)) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                        ->orWhere('sku', 'like', "%{$search}%");
                });
            }

            $products = $query->orderBy('name', 'asc')->limit(50)->get();

            return response()->json([
                'success' => true,
                'products' => $products->map(function ($product) {
                    return [
                        'id' => $product->id,
                        'name' => $product->name,
                        'sku' => $product->sku ?? '',
                        'unit' => $product->unit ? $product->unit->name : '',
                        'price' => $product->price ?? 0,
                        'tax_rate' => $product->tax ? $product->tax->rate : 0,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching products: '.$e->getMessage(),
                'products' => [],
            ], 500);
        }
    }

    /**
     * API: Get company settings (for BILL FROM)
     */
    public function getCompanySettings(): JsonResponse
    {
        try {
            $companySettings = \App\Models\CompanySetting::getSettings();

            $logoUrl = null;
            if ($companySettings->company_logo) {
                if (\Illuminate\Support\Facades\Storage::disk('public')->exists($companySettings->company_logo)) {
                    $logoUrl = asset('storage/'.$companySettings->company_logo);
                }
            }

            $resolvedCompanyId = $this->resolveCompanyIdFromSettings();

            return response()->json([
                'success' => true,
                'company' => [
                    'id' => $resolvedCompanyId,
                    'name' => $companySettings->company_name ?? '',
                    'email' => $companySettings->company_email ?? '',
                    'phone' => $companySettings->company_phone ?? '',
                    'fax' => $companySettings->company_fax ?? '',
                    'address' => $companySettings->company_address ?? '',
                    'city' => $companySettings->company_city ?? '',
                    'state' => $companySettings->company_state ?? '',
                    'zip' => $companySettings->company_zip ?? '',
                    'country' => $companySettings->company_country ?? '',
                    'tax_id' => $companySettings->company_tax_id ?? '',
                    'registration_number' => $companySettings->company_registration_number ?? '',
                    'logo' => $logoUrl,
                    'logo_path' => $companySettings->company_logo,
                ],
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching company settings: '.$e->getMessage(),
                'company' => null,
            ], 500);
        }
    }

    /**
     * API: Get bank accounts for dropdown (AJAX)
     */
    public function getBankAccounts(): JsonResponse
    {
        try {
            $bankAccounts = \App\Models\BankAccount::where('is_active', true)
                ->orderBy('account_name', 'asc')
                ->get();

            return response()->json([
                'success' => true,
                'bank_accounts' => $bankAccounts->map(function ($account) {
                    return [
                        'id' => $account->id,
                        'account_name' => $account->account_name,
                        'account_number' => $account->account_number,
                        'bank_name' => $account->bank_name,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching bank accounts: '.$e->getMessage(),
                'bank_accounts' => [],
            ], 500);
        }
    }

    /**
     * API: Get signatures for dropdown (AJAX)
     */
    public function getSignatures(): JsonResponse
    {
        try {
            $signatures = \App\Models\Signature::where('is_active', true)
                ->orderBy('name', 'asc')
                ->get();

            return response()->json([
                'success' => true,
                'signatures' => $signatures->map(function ($signature) {
                    return [
                        'id' => $signature->id,
                        'name' => $signature->name,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching signatures: '.$e->getMessage(),
                'signatures' => [],
            ], 500);
        }
    }

    /**
     * Resolve companies.id from general company settings (Bill From auto-load), or first active company.
     */
    private function resolveCompanyIdFromSettings(): ?int
    {
        $companySettings = \App\Models\CompanySetting::getSettings();
        $name = trim((string) ($companySettings->company_name ?? ''));
        $email = trim((string) ($companySettings->company_email ?? ''));

        $base = Company::query()->where('is_active', true);

        if ($name !== '') {
            $id = (clone $base)->where('name', $name)->value('id');
            if ($id !== null) {
                return (int) $id;
            }
        }

        if ($email !== '') {
            $id = (clone $base)->where('email', $email)->value('id');
            if ($id !== null) {
                return (int) $id;
            }
        }

        $id = Company::query()->where('is_active', true)->orderBy('id')->value('id');

        return $id !== null ? (int) $id : null;
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(DebitNote $debitNote): RedirectResponse
    {
        try {
            $debitNote->delete();

            return redirect()->route('admin.debit-notes.index')
                ->with('debit_note_deleted', 'Debit note deleted successfully.');
        } catch (\Exception $e) {
            return redirect()->route('admin.debit-notes.index')
                ->withErrors(['error' => 'Failed to delete debit note: '.$e->getMessage()]);
        }
    }
}
