<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\CashIn;
use App\Models\CustomAccount;
use App\Models\Client;
use App\Models\PaymentMethod;
use App\Models\PaymentType;
use App\Models\BankAccount;
use App\Models\Setting;
use App\Models\Consignment;
use App\Services\CurrencyService;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Auth;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Mail;
use App\Mail\InvoiceMail;
use App\Traits\HasSmtpConfig;
use Illuminate\Support\Facades\Log;

class CashInController extends Controller
{
    use HasSmtpConfig;

    /**
     * Display a listing of cash in records.
     */
    public function index(Request $request)
    {
        $dateFrom = $request->input('date_from');
        $dateTo = $request->input('date_to');
        $search = $request->input('search');
        $paymentStatus = $request->input('payment_status');

        $query = CashIn::with(['client', 'customAccount', 'paymentMethod']);

        if ($dateFrom) {
            $query->whereDate('date', '>=', $dateFrom);
        }
        if ($dateTo) {
            $query->whereDate('date', '<=', $dateTo);
        }
        if ($paymentStatus) {
            $query->where('payment_status', $paymentStatus);
        }
        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->whereHas('client', function ($q2) use ($search) {
                    $q2->where('first_name', 'like', "%{$search}%")
                       ->orWhere('last_name', 'like', "%{$search}%");
                })
                ->orWhere('transaction_id', 'like', "%{$search}%");
            });
        }

        if (auth()->user()->isAdmin() && $request->boolean('show_hidden')) {
            $query->withoutGlobalScope('visible');
        }

        $totalCashIn = $query->sum('amount');

        $perPage = preg_match('/Mobile|Android|iPhone/i', request()->header('User-Agent')) ? 10 : 20;
        $records = $query->latest('date')->paginate($perPage)->withQueryString();

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
        } catch (\Exception $e) {
            $currencySymbol = '£';
        }

        return view('cash-in.index', compact('records', 'totalCashIn', 'currencySymbol', 'dateFrom', 'dateTo', 'search', 'paymentStatus'));
    }

    /**
     * Show the form for creating a new cash in record.
     */
    public function create()
    {
        $clients = Client::orderBy('first_name')->get();
        $paymentMethods = PaymentMethod::all();
        $paymentTypes = PaymentType::where('direction', 'in')->get();
        $bankAccounts = BankAccount::all();
        $customAccounts = CustomAccount::all();
        $consignments = Consignment::where('status', 'active')->orderBy('title')->get();

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $baseCurrencyCode = Setting::where('key', 'base_currency_code')->value('value') ?? 'GBP';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $baseCurrencyCode = 'GBP';
        }

        try {
            $vatDefaultRate = Setting::where('key', 'vat_default_rate')->value('value') ?? '';
        } catch (\Exception $e) {
            $vatDefaultRate = '';
        }

        return view('cash-in.create', compact('clients', 'paymentMethods', 'paymentTypes', 'bankAccounts', 'customAccounts', 'consignments', 'currencySymbol', 'baseCurrencyCode', 'vatDefaultRate'));
    }

    /**
     * Store a newly created cash in record in storage.
     */
    public function store(Request $request)
    {
        if (Auth::user()->isAccountant()) {
            return redirect()->route('cash-in.index')->with('error', 'Accountants cannot create cash-in records.');
        }

        $recordType = $request->input('record_type', 'client');

        $rules = [
            'record_type' => 'required|in:client,custom',
            'date' => 'required|date',
            'amount' => 'required|numeric|min:0.01',
            'payment_method_id' => 'required|exists:payment_methods,id',
            'payment_type_id' => 'required|exists:payment_types,id',
            'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'transaction_id' => 'nullable|string|max:100',
            'receipt' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:5120',
            'notes' => 'nullable|string',
            'is_hidden' => 'nullable|boolean',
            'payment_status' => 'nullable|in:pending,paid',
            'consignment_id' => 'nullable|exists:consignments,id',
            'third_party_payer' => 'nullable|string|max:150',
            
            // Currency fields
            'original_currency' => 'nullable|string|size:3',
            'original_amount' => 'nullable|numeric|min:0.01',
            'exchange_rate' => 'nullable|numeric|min:0.000001',
        ];

        if ($recordType === 'custom') {
            $rules['custom_account_id'] = 'required|exists:custom_accounts,id';
        } else {
            $rules['client_id'] = 'required|exists:clients,id';
            $rules['sender_bank_name'] = 'nullable|string|max:150';
            $rules['sender_account_no'] = 'nullable|string|max:100';
            $rules['vat_inclusive'] = 'nullable|boolean';
            $rules['vat_rate'] = 'nullable|numeric|min:0|max:100';
        }

        $request->validate($rules);

        $receiptPath = null;
        if ($request->hasFile('receipt')) {
            $receiptPath = $request->file('receipt')->store('receipts/cash-in', 'public');
        }

        if ($recordType === 'custom') {
            $data = $request->only([
                'date', 'amount', 'payment_method_id', 'payment_type_id',
                'bank_account_id', 'transaction_id', 'custom_account_id', 'notes',
                'sender_bank_name', 'sender_account_no',
                'original_currency', 'original_amount', 'exchange_rate',
                'consignment_id'
            ]);
            $data['client_id'] = null;
            $data['third_party_payer'] = null;
            $data['vat_inclusive'] = null;
            $data['vat_rate'] = null;
        } else {
            $data = $request->only([
                'client_id', 'date', 'amount', 'payment_method_id', 'payment_type_id',
                'bank_account_id', 'sender_bank_name', 'sender_account_no', 'transaction_id',
                'notes', 'vat_inclusive', 'vat_rate',
                'original_currency', 'original_amount', 'exchange_rate',
                'consignment_id', 'third_party_payer'
            ]);
            $data['custom_account_id'] = null;
        }

        $data['receipt_path'] = $receiptPath;
        $data['created_by'] = Auth::id();
        $data['updated_by'] = Auth::id();
        $data['is_hidden'] = $request->boolean('is_hidden');
        $data['payment_status'] = $request->input('payment_status', 'pending');
        $data = $this->applyVat($data);

        CashIn::create($data);

        return redirect()->route('cash-in.index')->with('success', 'Cash In record saved successfully.');
    }

    /**
     * Display the specified cash in record.
     */
    public function show(CashIn $cashIn)
    {
        $cashIn->load(['client', 'paymentMethod', 'paymentType', 'bankAccount', 'creator']);

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $baseCurrencyCode = Setting::where('key', 'base_currency_code')->value('value') ?? 'GBP';
            $businessName = Setting::where('key', 'business_name')->value('value') ?? 'My Business';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $baseCurrencyCode = 'GBP';
            $businessName = 'My Business';
        }

        return view('cash-in.show', compact('cashIn', 'currencySymbol', 'baseCurrencyCode', 'businessName'));
    }

    /**
     * Show the form for editing the cash in record.
     */
    public function edit(CashIn $cashIn)
    {
        $clients = Client::orderBy('first_name')->get();
        $paymentMethods = PaymentMethod::all();
        $paymentTypes = PaymentType::where('direction', 'in')->get();
        $bankAccounts = BankAccount::all();
        $customAccounts = CustomAccount::all();
        $consignments = Consignment::orderBy('title')->get();

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $baseCurrencyCode = Setting::where('key', 'base_currency_code')->value('value') ?? 'GBP';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $baseCurrencyCode = 'GBP';
        }

        try {
            $vatDefaultRate = Setting::where('key', 'vat_default_rate')->value('value') ?? '';
        } catch (\Exception $e) {
            $vatDefaultRate = '';
        }

        return view('cash-in.edit', compact('cashIn', 'clients', 'paymentMethods', 'paymentTypes', 'bankAccounts', 'customAccounts', 'consignments', 'currencySymbol', 'baseCurrencyCode', 'vatDefaultRate'));
    }

    /**
     * Update the specified cash in record in storage.
     */
    public function update(Request $request, CashIn $cashIn)
    {
        if (Auth::user()->isAccountant()) {
            return redirect()->route('cash-in.index')->with('error', 'Accountants cannot edit cash-in records.');
        }

        $recordType = $request->input('record_type', 'client');

        $rules = [
            'record_type' => 'required|in:client,custom',
            'date' => 'required|date',
            'amount' => 'required|numeric|min:0.01',
            'payment_method_id' => 'required|exists:payment_methods,id',
            'payment_type_id' => 'required|exists:payment_types,id',
            'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'transaction_id' => 'nullable|string|max:100',
            'receipt' => 'nullable|file|mimes:pdf,jpg,jpeg,png|max:5120',
            'notes' => 'nullable|string',
            'is_hidden' => 'nullable|boolean',
            'payment_status' => 'nullable|in:pending,paid',
            'consignment_id' => 'nullable|exists:consignments,id',
            'third_party_payer' => 'nullable|string|max:150',

            // Currency fields
            'original_currency' => 'nullable|string|size:3',
            'original_amount' => 'nullable|numeric|min:0.01',
            'exchange_rate' => 'nullable|numeric|min:0.000001',
        ];

        if ($recordType === 'custom') {
            $rules['custom_account_id'] = 'required|exists:custom_accounts,id';
        } else {
            $rules['client_id'] = 'required|exists:clients,id';
            $rules['sender_bank_name'] = 'nullable|string|max:150';
            $rules['sender_account_no'] = 'nullable|string|max:100';
            $rules['vat_inclusive'] = 'nullable|boolean';
            $rules['vat_rate'] = 'nullable|numeric|min:0|max:100';
        }

        $request->validate($rules);

        $receiptPath = $cashIn->receipt_path;
        if ($request->hasFile('receipt')) {
            if ($receiptPath) {
                Storage::disk('public')->delete($receiptPath);
            }
            $receiptPath = $request->file('receipt')->store('receipts/cash-in', 'public');
        }

        if ($recordType === 'custom') {
            $data = $request->only([
                'date', 'amount', 'payment_method_id', 'payment_type_id',
                'bank_account_id', 'transaction_id', 'custom_account_id', 'notes',
                'sender_bank_name', 'sender_account_no',
                'original_currency', 'original_amount', 'exchange_rate',
                'consignment_id'
            ]);
            $data['client_id'] = null;
            $data['third_party_payer'] = null;
            $data['vat_inclusive'] = null;
            $data['vat_rate'] = null;
        } else {
            $data = $request->only([
                'client_id', 'date', 'amount', 'payment_method_id', 'payment_type_id',
                'bank_account_id', 'sender_bank_name', 'sender_account_no', 'transaction_id',
                'notes', 'vat_inclusive', 'vat_rate',
                'original_currency', 'original_amount', 'exchange_rate',
                'consignment_id', 'third_party_payer'
            ]);
            $data['custom_account_id'] = null;
        }

        $data['receipt_path'] = $receiptPath;
        $data['updated_by'] = Auth::id();
        $data['is_hidden'] = $request->boolean('is_hidden');
        $data['payment_status'] = $request->input('payment_status', 'pending');
        $data = $this->applyVat($data);

        $cashIn->update($data);

        return redirect()->route('cash-in.show', $cashIn->id)->with('success', 'Cash In record updated successfully.');
    }

    /**
     * Remove the specified cash in record from storage.
     */
    public function destroy(CashIn $cashIn)
    {
        if (Auth::user()->isAccountant()) {
            return redirect()->route('cash-in.index')->with('error', 'Accountants cannot delete cash-in records.');
        }
        if ($cashIn->receipt_path) {
            Storage::disk('public')->delete($cashIn->receipt_path);
        }

        $cashIn->delete();

        return redirect()->route('cash-in.index')->with('success', 'Cash In record deleted successfully.');
    }

    /**
     * Download transaction receipt.
     */
    public function downloadReceipt(CashIn $cashIn)
    {
        if (!$cashIn->receipt_path || !Storage::disk('public')->exists($cashIn->receipt_path)) {
            return back()->with('error', 'Receipt file does not exist.');
        }

        return Storage::disk('public')->download($cashIn->receipt_path);
    }

    /**
     * Generate PDF transaction details.
     */
    public function downloadPdf(CashIn $cashIn)
    {
        $cashIn->load(['client', 'customAccount', 'paymentMethod', 'paymentType', 'bankAccount']);

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $businessName = Setting::where('key', 'business_name')->value('value') ?? 'My Business';
            $businessEmail = Setting::where('key', 'business_email')->value('value') ?? '';
            $businessPhone = Setting::where('key', 'business_phone')->value('value') ?? '';
            $businessAddress = Setting::where('key', 'business_address')->value('value') ?? '';
            $invoiceLogo = Setting::where('key', 'invoice_logo')->value('value') ?? '';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $businessName = 'My Business';
            $businessEmail = '';
            $businessPhone = '';
            $businessAddress = '';
            $invoiceLogo = '';
        }

        $template = $cashIn->custom_account_id
            ? 'reports.templates.custom_account_cash_in_invoice'
            : 'reports.templates.cash_in_receipt';

        $pdf = Pdf::loadView($template, compact('cashIn', 'currencySymbol', 'businessName', 'businessEmail', 'businessPhone', 'businessAddress', 'invoiceLogo'));

        return $pdf->download("CashIn_Receipt_TXN" . ($cashIn->transaction_id ?? $cashIn->id) . ".pdf");
    }

    public function sendEmail(Request $request, CashIn $cashIn)
    {
        $request->validate(['email' => 'required|email', 'subject' => 'nullable|string|max:255', 'message' => 'nullable|string|max:5000']);

        $cashIn->load(['client', 'customAccount', 'paymentMethod', 'paymentType', 'bankAccount']);

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $businessName = Setting::where('key', 'business_name')->value('value') ?? 'My Business';
            $businessEmail = Setting::where('key', 'business_email')->value('value') ?? '';
            $businessPhone = Setting::where('key', 'business_phone')->value('value') ?? '';
            $businessAddress = Setting::where('key', 'business_address')->value('value') ?? '';
            $invoiceLogo = Setting::where('key', 'invoice_logo')->value('value') ?? '';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $businessName = 'My Business';
            $businessEmail = '';
            $businessPhone = '';
            $businessAddress = '';
            $invoiceLogo = '';
        }

        $this->applySmtpConfig();

        try {
            Mail::to($request->email)->send(new InvoiceMail('cash-in', $cashIn, $businessName, $currencySymbol, $request->subject, $request->message, compact('businessEmail', 'businessPhone', 'businessAddress', 'invoiceLogo')));
            return back()->with('success', 'Invoice emailed successfully to ' . $request->email);
        } catch (\Exception $e) {
            Log::error('CashIn email failed: ' . $e->getMessage(), ['exception' => $e, 'cash_in_id' => $cashIn->id]);
            return back()->with('error', 'Failed to send email: ' . $e->getMessage());
        }
    }

    public function shareWhatsApp(CashIn $cashIn)
    {
        $cashIn->load(['client', 'paymentMethod', 'paymentType', 'bankAccount']);

        try {
            $currencySymbol = Setting::where('key', 'currency_symbol')->value('value') ?? '£';
            $businessName = Setting::where('key', 'business_name')->value('value') ?? 'My Business';
            $businessEmail = Setting::where('key', 'business_email')->value('value') ?? '';
            $businessPhone = Setting::where('key', 'business_phone')->value('value') ?? '';
            $businessAddress = Setting::where('key', 'business_address')->value('value') ?? '';
            $invoiceLogo = Setting::where('key', 'invoice_logo')->value('value') ?? '';
        } catch (\Exception $e) {
            $currencySymbol = '£';
            $businessName = 'My Business';
            $businessEmail = '';
            $businessPhone = '';
            $businessAddress = '';
            $invoiceLogo = '';
        }

        $pdf = Pdf::loadView('reports.templates.cash_in_receipt', compact('cashIn', 'currencySymbol', 'businessName', 'businessEmail', 'businessPhone', 'businessAddress', 'invoiceLogo'));

        $filename = 'temp/invoice_cashin_' . $cashIn->id . '_' . time() . '.pdf';
        Storage::disk('public')->put($filename, $pdf->output());
        $pdfUrl = url('serve-storage/' . $filename);

        $this->cleanupTempFiles();

        $text = "{$businessName} - Cash In Receipt\n"
            . "Client: " . ($cashIn->client?->full_name ?? 'N/A') . "\n"
            . "Amount: {$currencySymbol}" . number_format($cashIn->amount, 2) . "\n"
            . "Date: " . $cashIn->date->format('d M Y') . "\n"
            . "Transaction: " . ($cashIn->transaction_id ?? 'N/A');

        return response()->json([
            'pdf_url' => $pdfUrl,
            'filename' => "CashIn_Receipt_TXN" . ($cashIn->transaction_id ?? $cashIn->id) . ".pdf",
            'text' => $text,
        ]);
    }

    private function cleanupTempFiles(): void
    {
        try {
            $tempDir = storage_path('app/public/temp');
            if (is_dir($tempDir)) {
                foreach (glob($tempDir . '/invoice_*') as $file) {
                    if (filemtime($file) < now()->subHour()->timestamp) {
                        @unlink($file);
                    }
                }
            }
        } catch (\Exception $e) {}
    }

    public function createClientInline(Request $request)
    {
        if (Auth::user()->isAccountant()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $validated = $request->validate([
            'title' => 'required|string',
            'first_name' => 'required|string|max:255',
            'last_name' => 'required|string|max:255',
            'email' => 'nullable|email|max:255',
            'phone' => 'nullable|string|max:50',
            'mobile' => 'nullable|string|max:50',
            'company_name' => 'nullable|string|max:255',
            'company_vat' => 'nullable|string|max:100',
            'address_line1' => 'nullable|string|max:255',
            'address_line2' => 'nullable|string|max:255',
            'city' => 'nullable|string|max:100',
            'state' => 'nullable|string|max:100',
            'postcode' => 'nullable|string|max:20',
            'country' => 'nullable|string|max:100',
        ]);

        $validated['created_by'] = Auth::id();

        $client = Client::create($validated);

        return response()->json([
            'success' => true,
            'client' => [
                'id' => $client->id,
                'name' => $client->full_name,
                'phone' => $client->phone ?? '',
                'email' => $client->email ?? '',
            ]
        ]);
    }

    public function createCustomAccountInline(Request $request)
    {
        if (Auth::user()->isAccountant()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'nullable|email|max:255',
            'account_type' => 'required|string|max:255',
            'notes' => 'nullable|string',
        ]);

        $validated['created_by'] = Auth::id();

        $account = CustomAccount::create($validated);

        return response()->json([
            'success' => true,
            'account' => [
                'id' => $account->id,
                'name' => $account->name,
                'type' => $account->account_type,
            ]
        ]);
    }

    /**
     * AJAX endpoint to fetch exchange rate on-the-fly.
     */
    public function fetchExchangeRate(Request $request)
    {
        $request->validate([
            'date' => 'required|date',
            'from' => 'required|string|size:3',
        ]);

        try {
            $baseCurrency = Setting::where('key', 'base_currency_code')->value('value') ?? 'GBP';
        } catch (\Exception $e) {
            $baseCurrency = 'GBP';
        }

        $date = $request->input('date');
        $from = strtoupper($request->input('from'));

        $service = app(CurrencyService::class);
        $rate = $service->getRate($date, $from, $baseCurrency);

        if ($rate !== null) {
            return response()->json([
                'success' => true,
                'rate' => $rate,
                'base' => $baseCurrency
            ]);
        }

        return response()->json([
            'success' => false,
            'message' => 'Failed to fetch exchange rate. Check network connection or configuration.'
        ], 422);
    }

    private function applyVat(array $data): array
    {
        $data['vat_inclusive'] = !empty($data['vat_inclusive']);

        if (!empty($data['vat_rate']) && isset($data['amount'])) {
            $vatRate = $data['vat_rate'] / 100;

            if ($data['vat_inclusive']) {
                $data['net_amount'] = round($data['amount'] / (1 + $vatRate), 2);
                $data['vat_amount'] = round($data['amount'] - ($data['amount'] / (1 + $vatRate)), 2);
            } else {
                $data['net_amount'] = $data['amount'];
                $data['vat_amount'] = round($data['amount'] * $vatRate, 2);
            }
        } else {
            $data['vat_rate'] = null;
            $data['net_amount'] = $data['amount'] ?? 0;
            $data['vat_amount'] = 0;
        }
        return $data;
    }
}
