<?php

namespace App\Http\Controllers\Admin;

use App\Core\Repositories\CustomerRepository;
use App\Core\Repositories\QuotationRepository;
use App\Core\Services\Quotation\QuotationPdfService;
use App\Core\Services\Quotation\QuotationService;
use App\Http\Controllers\Controller;
use App\Models\Quotation;
use App\Services\ReminderService;
use App\Support\QuotationTemplateResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class QuotationController extends Controller
{
    public function __construct(
        private QuotationService $quotationService,
        private QuotationRepository $quotationRepository,
        private CustomerRepository $customerRepository,
        private QuotationPdfService $quotationPdfService,
        private ReminderService $reminderService
    ) {}

    /**
     * Display a listing of quotations
     */
    public function index(Request $request): View|StreamedResponse
    {
        $this->authorize('viewAny', Quotation::class);

        $filters = [
            'status' => $request->get('status'),
            'customer_id' => $request->get('customer_id'),
            'date_from' => $request->get('date_from'),
            'date_to' => $request->get('date_to'),
            'search' => $request->get('search'),
        ];

        if ($request->get('export') === 'csv') {
            return $this->exportQuotationsCsv($filters);
        }

        $perPage = $request->get('per_page', 15);
        $quotations = $this->quotationRepository->getPaginated($perPage, $filters);
        $customers = $this->customerRepository->getAll();

        return view('admin.quotation.index', [
            'quotations' => $quotations,
            'customers' => $customers,
            'filters' => $filters,
        ]);
    }

    /**
     * Show the form for creating a new quotation
     */
    public function create(): View
    {
        $this->authorize('create', Quotation::class);

        $customers = $this->customerRepository->getAll();
        $companySettings = \App\Models\CompanySetting::getSettings();
        $localizationSettings = \App\Models\LocalizationSetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $quotationSettings = \App\Models\QuotationSetting::getSettings();
        $nextQuotationNumber = $this->quotationRepository->generateQuotationNumber();
        $bankAccounts = \App\Models\BankAccount::where('is_active', true)->orderBy('bank_name')->get();

        // Get default validity days
        $validityDays = $quotationSettings->validity_days ?? 30;
        $defaultExpiryDate = now()->addDays($validityDays)->format('Y-m-d');

        return view('admin.quotation.create', [
            'customers' => $customers,
            'companySettings' => $companySettings,
            'localizationSettings' => $localizationSettings,
            'currencies' => $currencies,
            'signatures' => $signatures,
            'quotationSettings' => $quotationSettings,
            'nextQuotationNumber' => $nextQuotationNumber,
            'defaultExpiryDate' => $defaultExpiryDate,
            'bankAccounts' => $bankAccounts,
        ]);
    }

    /**
     * API: Get company settings for auto-loading
     */
    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);
                }
            }

            return response()->json([
                'success' => true,
                'company' => [
                    '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);
        }
    }

    /**
     * Preview quotation before creating
     */
    public function preview(Request $request): View
    {
        $this->authorize('create', Quotation::class);

        // Get form data
        $data = $request->all();

        // Get related data
        $companySettings = \App\Models\CompanySetting::getSettings();
        $customers = $this->customerRepository->getAll();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();

        // Get customer if selected
        $customer = null;
        if (! empty($data['customer_id'])) {
            $customer = $this->customerRepository->getById($data['customer_id']);
        }

        // Get selected currency
        $selectedCurrency = $currencies->where('code', $data['currency'] ?? 'USD')->first();

        // Calculate totals
        $subtotal = 0;
        $taxAmount = 0;
        $items = [];

        if (! empty($data['items'])) {
            foreach ($data['items'] as $item) {
                $quantity = floatval($item['quantity'] ?? 0);
                $unitPrice = floatval($item['unit_price'] ?? 0);
                $taxRate = floatval($item['tax_rate'] ?? 0);

                $itemSubtotal = $quantity * $unitPrice;
                $itemTax = $itemSubtotal * ($taxRate / 100);

                $subtotal += $itemSubtotal;
                $taxAmount += $itemTax;

                $items[] = [
                    'description' => $item['description'] ?? '',
                    'notes' => $item['notes'] ?? '',
                    'quantity' => $quantity,
                    'unit_price' => $unitPrice,
                    'tax_rate' => $taxRate,
                    'unit' => $item['unit'] ?? null,
                    'total' => $itemSubtotal + $itemTax,
                ];
            }
        }

        // Calculate discount
        $discountType = $data['discount_type'] ?? 'fixed';
        $discountAmount = floatval($data['discount_amount'] ?? 0);
        $discount = 0;

        if ($discountType === 'percentage') {
            $discount = $subtotal * ($discountAmount / 100);
        } else {
            $discount = $discountAmount;
        }

        $total = $subtotal + $taxAmount - $discount;

        $templateKey = ! empty($data['template'])
            ? QuotationTemplateResolver::normalize($data['template'])
            : QuotationTemplateResolver::resolveDefaultKey();
        $templateView = 'quotations.templates.'.$templateKey.'.web';
        if (! view()->exists($templateView)) {
            $templateView = QuotationTemplateResolver::view($templateKey);
        }

        // Create a mock quotation object for template compatibility
        // Templates expect $quotation variable
        $quotation = (object) [
            'quotation_number' => $data['quotation_number'] ?? 'QUO-001',
            'issue_date' => \Carbon\Carbon::parse($data['issue_date'] ?? now()),
            'expiry_date' => ! empty($data['expiry_date']) ? \Carbon\Carbon::parse($data['expiry_date']) : now()->addDays(30),
            'status' => $data['status'] ?? 'draft',
            'subtotal' => $subtotal,
            'tax_amount' => $taxAmount,
            'discount_amount' => $discount,
            'total' => $total,
            'currency' => $data['currency'] ?? \App\Models\Currency::getDefaultCode(),
            'notes' => $data['notes'] ?? null,
            'terms' => $data['terms'] ?? null,
            'template' => $templateKey,
            'customer' => $customer,
            'items' => collect($items)->map(function ($item) {
                return (object) [
                    'description' => $item['description'],
                    'notes' => $item['notes'] ?? null,
                    'quantity' => $item['quantity'],
                    'unit_price' => $item['unit_price'],
                    'tax_rate' => $item['tax_rate'],
                    'unit' => $item['unit'] ?? null,
                ];
            }),
        ];

        return view('admin.quotation.preview', [
            'data' => $data,
            'companySettings' => $companySettings,
            'customer' => $customer,
            'currencies' => $currencies,
            'selectedCurrency' => $selectedCurrency,
            'signatures' => $signatures,
            'items' => $items,
            'subtotal' => $subtotal,
            'taxAmount' => $taxAmount,
            'discount' => $discount,
            'total' => $total,
            'templateView' => $templateView,
            'quotation' => $quotation,
        ]);
    }

    /**
     * Store a newly created quotation
     */
    public function store(Request $request): RedirectResponse
    {
        $this->authorize('create', Quotation::class);

        $validated = $request->validate([
            'quotation_number' => 'nullable|string|unique:quotations,quotation_number',
            'customer_id' => 'required|exists:customers,id',
            'issue_date' => 'required|date',
            'expiry_date' => 'nullable|date|after_or_equal:issue_date',
            'status' => 'nullable|in:draft,sent,viewed,accepted,rejected,expired,converted,cancelled',
            'currency' => 'nullable|string|size:3',
            'exchange_rate' => 'nullable|numeric|min:0',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'discount_amount' => 'nullable|numeric|min:0',
            'discount_type' => 'nullable|in:fixed,percentage',
            'reference_number' => 'nullable|string',
            'sales_person' => 'nullable|string',
            'items' => 'required|array|min:1',
            'items.*.description' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0|max:100',
            'items.*.unit' => 'nullable|string',
            'items.*.notes' => 'nullable|string',
            'template' => 'nullable|string|in:modern,classic,minimal,bold',
        ]);

        $quotation = $this->quotationService->create($validated);

        try {
            $this->reminderService->sendQuotationCreated($quotation->fresh(['customer']));
        } catch (\Throwable) {
        }

        return redirect()
            ->route('admin.quotations.show', $quotation)
            ->with('success', 'Quotation created successfully.');
    }

    /**
     * Display the specified quotation
     */
    public function show(Quotation $quotation): View
    {
        $this->authorize('view', $quotation);

        $quotation->load([
            'customer',
            'items',
            'creator',
            'reminderLogs' => fn ($q) => $q->orderByDesc('id')->limit(20),
        ]);
        $templateView = QuotationTemplateResolver::resolvedWebViewForQuotation($quotation);
        $whatsappConfig = \App\Models\WhatsAppConfiguration::getActive();
        $whatsappSettings = \App\Models\WhatsAppConfiguration::query()->latest('id')->first();
        $emailConfig = \App\Models\EmailConfiguration::getActive();

        return view('admin.quotation.show', [
            'quotation' => $quotation,
            'templateView' => $templateView,
            'whatsappConfig' => $whatsappConfig,
            'whatsappSettings' => $whatsappSettings,
            'emailConfig' => $emailConfig,
        ]);
    }

    /**
     * Show the form for editing the specified quotation
     */
    public function edit(Quotation $quotation): View
    {
        $this->authorize('update', $quotation);

        $quotation->load(['customer', 'items']);
        $customers = $this->customerRepository->getAll();
        $companySettings = \App\Models\CompanySetting::getSettings();
        $localizationSettings = \App\Models\LocalizationSetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();

        return view('admin.quotation.edit', [
            'quotation' => $quotation,
            'customers' => $customers,
            'companySettings' => $companySettings,
            'localizationSettings' => $localizationSettings,
            'currencies' => $currencies,
            'signatures' => $signatures,
        ]);
    }

    /**
     * Update the specified quotation
     */
    public function update(Request $request, Quotation $quotation): RedirectResponse
    {
        $this->authorize('update', $quotation);

        $previousStatus = $quotation->status;

        $validated = $request->validate([
            'customer_id' => 'required|exists:customers,id',
            'issue_date' => 'required|date',
            'expiry_date' => 'nullable|date|after_or_equal:issue_date',
            'status' => 'nullable|in:draft,sent,viewed,accepted,rejected,expired,converted,cancelled',
            'currency' => 'nullable|string|size:3',
            'exchange_rate' => 'nullable|numeric|min:0',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'discount_amount' => 'nullable|numeric|min:0',
            'discount_type' => 'nullable|in:fixed,percentage',
            'reference_number' => 'nullable|string',
            'sales_person' => 'nullable|string',
            'items' => 'required|array|min:1',
            'items.*.description' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0|max:100',
            'items.*.unit' => 'nullable|string',
            'items.*.notes' => 'nullable|string',
            'template' => 'nullable|string|in:modern,classic,minimal,bold',
        ]);

        $quotation = $this->quotationService->update($quotation, $validated);
        $quotation->refresh();

        if ($previousStatus !== $quotation->status) {
            try {
                if ($quotation->status === 'accepted') {
                    $this->reminderService->sendQuotationAccepted($quotation->load('customer'));
                }
                if ($quotation->status === 'rejected') {
                    $this->reminderService->sendQuotationRejected($quotation->load('customer'));
                }
            } catch (\Throwable) {
            }
        }

        return redirect()
            ->route('admin.quotations.show', $quotation)
            ->with('success', 'Quotation updated successfully.');
    }

    /**
     * Convert quotation to invoice
     */
    public function convertToInvoice(Request $request, Quotation $quotation): RedirectResponse
    {
        $this->authorize('update', $quotation);

        if (! $quotation->canBeConverted()) {
            return redirect()
                ->route('admin.quotations.show', $quotation)
                ->with('error', 'This quotation cannot be converted to an invoice.');
        }

        try {
            $invoice = $this->quotationService->convertToInvoice($quotation, [
                'due_date' => $request->input('due_date', now()->addDays(30)->format('Y-m-d')),
            ]);

            return redirect()
                ->route('admin.invoices.show', $invoice)
                ->with('success', 'Quotation converted to invoice successfully.');
        } catch (\Exception $e) {
            return redirect()
                ->route('admin.quotations.show', $quotation)
                ->with('error', 'Failed to convert quotation: '.$e->getMessage());
        }
    }

    /**
     * Remove the specified quotation
     */
    public function destroy(Quotation $quotation): RedirectResponse
    {
        $this->authorize('delete', $quotation);

        $this->quotationService->delete($quotation);

        return redirect()
            ->route('admin.quotations.index')
            ->with('success', 'Quotation deleted successfully.');
    }

    /**
     * Send quotation via email with PDF attachment.
     */
    public function sendEmail(Request $request, Quotation $quotation): JsonResponse
    {
        $this->authorize('send', $quotation);

        $request->validate([
            'email' => 'required|email',
        ]);

        $emailConfig = \App\Models\EmailConfiguration::getActive();
        if (! $emailConfig || ! $emailConfig->is_active) {
            return response()->json([
                'success' => false,
                'message' => 'Email configuration is not set up. Please configure email settings first.',
            ], 400);
        }

        try {
            $quotation->loadMissing('customer');
            $pdfContent = $this->quotationPdfService->generate($quotation);
            $filename = 'quotation-'.$quotation->quotation_number.'.pdf';
            $toEmail = trim((string) $request->input('email'));
            $companySettings = \App\Models\CompanySetting::getSettings();

            Mail::raw(
                'Hello '.($quotation->customer->name ?? 'Customer').",\n\n".
                "Please find your quotation #{$quotation->quotation_number} attached.\n\n".
                "Thank you,\n".($companySettings->company_name ?? config('app.name')),
                function ($message) use ($toEmail, $quotation, $pdfContent, $filename) {
                    $message->to($toEmail)
                        ->subject('Quotation '.$quotation->quotation_number)
                        ->attachData($pdfContent, $filename, ['mime' => 'application/pdf']);
                }
            );

            return response()->json([
                'success' => true,
                'message' => 'Quotation sent successfully to '.$toEmail,
            ]);
        } catch (\Throwable $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send quotation email: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * Send quotation PDF via WhatsApp Business API.
     */
    public function sendWhatsApp(Request $request, Quotation $quotation): JsonResponse
    {
        $this->authorize('send', $quotation);

        $request->validate([
            'phone' => 'nullable|string',
        ]);

        try {
            $phone = trim((string) $request->input('phone', ''));
            if ($phone === '') {
                $quotation->loadMissing('customer');
                $phone = trim((string) ($quotation->customer->phone ?? ''));
            }
            if ($phone === '') {
                return response()->json([
                    'success' => false,
                    'message' => 'No WhatsApp recipient number found. Add a phone on the customer or enter one.',
                ], 422);
            }

            $whatsappService = new \App\Core\Services\WhatsAppService;

            $pdfContent = $this->quotationPdfService->generate($quotation);
            $filename = 'quotations/quotation_'.$quotation->quotation_number.'_'.time().'.pdf';
            Storage::disk('public')->put($filename, $pdfContent);
            $documentUrl = Storage::disk('public')->url($filename);

            $companySettings = \App\Models\CompanySetting::getSettings();
            $quotation->load('customer');
            $message = 'Hello '.($quotation->customer->name ?? 'Customer').",\n\n";
            $message .= "Your quotation #{$quotation->quotation_number} is ready.\n\n";
            $message .= 'Amount: '.number_format($quotation->total, 2)." {$quotation->currency}\n";
            if ($quotation->expiry_date) {
                $message .= 'Valid until: '.$quotation->expiry_date->format('M d, Y')."\n\n";
            }
            $message .= "Please find the quotation attached.\n\n";
            $message .= "Thank you,\n".($companySettings->company_name ?? config('app.name'));

            $result = $whatsappService->send($phone, $message, $documentUrl, 'document');

            if ($result['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Quotation sent successfully via WhatsApp to '.$phone,
                ]);
            }

            return response()->json([
                'success' => false,
                'message' => $result['message'],
            ], 400);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send quotation via WhatsApp: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * Public share link for this quotation.
     */
    public function getShareLink(Quotation $quotation): JsonResponse
    {
        $this->authorize('view', $quotation);

        if (empty($quotation->public_token)) {
            $quotation->public_token = Str::random(32);
            $quotation->save();
        }

        $publicBase = trim((string) config('invoice.public_base_url', ''));
        $shareLink = $publicBase !== ''
            ? rtrim($publicBase, '/').'/quotation/'.$quotation->public_token
            : route('quotation.public', ['token' => $quotation->public_token], absolute: true);

        return response()->json([
            'success' => true,
            'link' => $shareLink,
        ]);
    }

    public function downloadPdf(Quotation $quotation)
    {
        $this->authorize('downloadPdf', $quotation);

        return $this->quotationPdfService->download($quotation);
    }

    /**
     * Minimal print-friendly page (opens in new tab, triggers print dialog).
     */
    public function printView(Quotation $quotation): View
    {
        $this->authorize('view', $quotation);

        $quotation->load(['customer', 'items']);
        $templateView = QuotationTemplateResolver::resolvedWebViewForQuotation($quotation);

        return view('admin.quotation.print', [
            'quotation' => $quotation,
            'templateView' => $templateView,
        ]);
    }

    /**
     * JSON for send modals (email / phone defaults).
     */
    public function getQuotationData(Quotation $quotation): JsonResponse
    {
        $this->authorize('view', $quotation);

        $quotation->load('customer');
        $companySettings = \App\Models\CompanySetting::getSettings();

        return response()->json([
            'quotation_number' => $quotation->quotation_number,
            'customer_name' => $quotation->customer->name ?? 'N/A',
            'customer_email' => $quotation->customer->email ?? '',
            'customer_phone' => $quotation->customer->phone ?? '',
            'total' => $quotation->total,
            'currency' => $quotation->currency,
            'issue_date' => $quotation->issue_date?->toIso8601String(),
            'company_name' => $companySettings->company_name ?? config('app.name'),
        ]);
    }

    private function exportQuotationsCsv(array $filters): StreamedResponse
    {
        $rows = $this->quotationRepository->getFilteredCollection($filters);

        $filename = 'quotations-'.now()->format('Y-m-d-His').'.csv';

        return response()->streamDownload(function () use ($rows) {
            $out = fopen('php://output', 'w');
            fputcsv($out, ['Quotation #', 'Customer', 'Email', 'Issue date', 'Expiry', 'Status', 'Currency', 'Total']);
            foreach ($rows as $q) {
                fputcsv($out, [
                    $q->quotation_number,
                    $q->customer->name ?? '',
                    $q->customer->email ?? '',
                    $q->issue_date?->format('Y-m-d') ?? '',
                    $q->expiry_date?->format('Y-m-d') ?? '',
                    $q->status,
                    $q->currency,
                    $q->total,
                ]);
            }
            fclose($out);
        }, $filename, [
            'Content-Type' => 'text/csv; charset=UTF-8',
        ]);
    }
}
