<?php

namespace App\Services;

use App\Models\CreditNote;
use App\Models\DeliveryNote;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\LedgerEntry;
use App\Models\Order;
use App\Models\Quote;
use App\Models\QuoteItem;
use App\Models\Supplier;
use App\Models\SupplierPayout;
use App\Models\SupplierTransaction;
use Illuminate\Support\Facades\DB;

class FinanceService
{
    /**
     * Create an invoice from an order
     */
    public function createInvoiceFromOrder(Order $order): Invoice
    {
        $order->load(['items', 'user', 'company']);

        $invoice = Invoice::create([
            'invoice_number' => Invoice::generateInvoiceNumber(),
            'order_id' => $order->id,
            'user_id' => $order->user_id,
            'company_id' => $order->company_id,
            'status' => 'draft',
            'subtotal' => $order->subtotal,
            'tax_amount' => $order->tax_amount,
            'delivery_fee' => $order->delivery_fee,
            'discount_amount' => 0,
            'total_amount' => $order->total_amount,
            'amount_paid' => 0,
            'balance_due' => $order->total_amount,
            'issue_date' => now(),
            'due_date' => $order->payment_method === '30_days' ? now()->addDays(30) : now()->addDays(7),
            'payment_terms' => $order->payment_method === '30_days' ? '30 days' : '7 days',
        ]);

        foreach ($order->items as $item) {
            InvoiceItem::create([
                'invoice_id' => $invoice->id,
                'product_id' => $item->product_id,
                'supplier_id' => $item->supplier_id,
                'product_name' => $item->product_name,
                'product_sku' => $item->product_sku,
                'quantity' => $item->quantity,
                'unit_price' => $item->unit_price,
                'total_price' => $item->total_price,
            ]);
        }

        // Record in ledger
        LedgerEntry::recordIncome(
            $order->total_amount,
            'sales',
            "Invoice {$invoice->invoice_number} created for order {$order->order_number}",
            $invoice,
            $order->user_id,
            null,
            $order->company_id
        );

        return $invoice;
    }

    /**
     * Create a delivery note from an order
     */
    public function createDeliveryNote(Order $order, ?int $supplierId = null): DeliveryNote
    {
        return DeliveryNote::create([
            'delivery_note_number' => DeliveryNote::generateDeliveryNoteNumber(),
            'order_id' => $order->id,
            'supplier_id' => $supplierId,
            'status' => 'pending',
            'delivery_method' => $order->delivery_method,
            'delivery_address' => $order->delivery_address,
            'delivery_city' => $order->delivery_city,
            'delivery_postal_code' => $order->delivery_postal_code,
            'recipient_name' => $order->user->name ?? null,
            'recipient_phone' => $order->company->contact_phone ?? null,
        ]);
    }

    /**
     * Create a quote
     */
    public function createQuote(array $data, array $items): Quote
    {
        $quote = Quote::create([
            'quote_number' => Quote::generateQuoteNumber(),
            'user_id' => $data['user_id'],
            'company_id' => $data['company_id'] ?? null,
            'supplier_id' => $data['supplier_id'] ?? null,
            'status' => 'draft',
            'valid_until' => now()->addDays(14),
            'notes' => $data['notes'] ?? null,
            'terms' => $data['terms'] ?? 'Quote valid for 14 days. Prices subject to change.',
        ]);

        foreach ($items as $item) {
            QuoteItem::create([
                'quote_id' => $quote->id,
                'product_id' => $item['product_id'] ?? null,
                'product_name' => $item['product_name'],
                'product_sku' => $item['product_sku'] ?? null,
                'quantity' => $item['quantity'],
                'unit_price' => $item['unit_price'],
                'total_price' => $item['quantity'] * $item['unit_price'],
            ]);
        }

        $quote->calculateTotals();

        return $quote;
    }

    /**
     * Create a credit note
     */
    public function createCreditNote(Invoice $invoice, float $amount, string $reason): CreditNote
    {
        $creditNote = CreditNote::create([
            'credit_note_number' => CreditNote::generateCreditNoteNumber(),
            'invoice_id' => $invoice->id,
            'order_id' => $invoice->order_id,
            'user_id' => $invoice->user_id,
            'status' => 'issued',
            'amount' => $amount,
            'reason' => $reason,
            'issue_date' => now(),
        ]);

        // Update invoice
        $invoice->balance_due -= $amount;
        if ($invoice->balance_due <= 0) {
            $invoice->status = 'refunded';
            $invoice->balance_due = 0;
        }
        $invoice->save();

        // Record in ledger
        LedgerEntry::recordExpense(
            $amount,
            'refund',
            "Credit note {$creditNote->credit_note_number} issued for invoice {$invoice->invoice_number}",
            $creditNote,
            $invoice->user_id
        );

        return $creditNote;
    }

    /**
     * Process supplier payout
     */
    public function processSupplierPayout(Supplier $supplier, string $periodStart, string $periodEnd): ?SupplierPayout
    {
        $transactions = SupplierTransaction::where('supplier_id', $supplier->id)
            ->where('status', 'pending')
            ->whereBetween('created_at', [$periodStart, $periodEnd])
            ->get();

        if ($transactions->isEmpty()) {
            return null;
        }

        $grossAmount = $transactions->sum('amount');
        $commissionAmount = $transactions->sum('commission_amount');
        $netAmount = $transactions->sum('net_amount');

        $payout = SupplierPayout::create([
            'payout_number' => SupplierPayout::generatePayoutNumber(),
            'supplier_id' => $supplier->id,
            'status' => 'pending',
            'gross_amount' => $grossAmount,
            'commission_amount' => $commissionAmount,
            'net_amount' => $netAmount,
            'period_start' => $periodStart,
            'period_end' => $periodEnd,
        ]);

        // Mark transactions as processed
        $transactions->each(function ($transaction) use ($payout) {
            $transaction->update(['status' => 'processed']);
        });

        // Record in ledger
        LedgerEntry::recordExpense(
            $netAmount,
            'supplier_payout',
            "Payout {$payout->payout_number} to supplier {$supplier->company_name}",
            $payout,
            null,
            $supplier->id
        );

        // Record commission as income
        LedgerEntry::recordIncome(
            $commissionAmount,
            'commission',
            "Commission from payout {$payout->payout_number}",
            $payout,
            null,
            $supplier->id
        );

        return $payout;
    }

    /**
     * Get financial dashboard data
     */
    public function getDashboardData(): array
    {
        $today = now();
        $startOfMonth = $today->copy()->startOfMonth();
        $startOfYear = $today->copy()->startOfYear();

        // Revenue metrics
        $monthlyRevenue = Invoice::where('status', 'paid')
            ->where('paid_date', '>=', $startOfMonth)
            ->sum('total_amount');

        $yearlyRevenue = Invoice::where('status', 'paid')
            ->where('paid_date', '>=', $startOfYear)
            ->sum('total_amount');

        $totalRevenue = Invoice::where('status', 'paid')->sum('total_amount');

        // Outstanding amounts
        $totalOutstanding = Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])
            ->sum('balance_due');

        // Aging report
        $aging = $this->getAgingReport();

        // Commission earned
        $monthlyCommission = LedgerEntry::where('category', 'commission')
            ->where('created_at', '>=', $startOfMonth)
            ->sum('amount');

        $totalCommission = LedgerEntry::where('category', 'commission')->sum('amount');

        // Supplier payouts
        $pendingPayouts = SupplierPayout::where('status', 'pending')->sum('net_amount');
        $completedPayouts = SupplierPayout::where('status', 'completed')->sum('net_amount');

        // Order statistics
        $monthlyOrders = Order::where('created_at', '>=', $startOfMonth)->count();
        $pendingOrders = Order::where('status', 'pending')->count();

        return [
            'revenue' => [
                'monthly' => $monthlyRevenue,
                'yearly' => $yearlyRevenue,
                'total' => $totalRevenue,
            ],
            'outstanding' => $totalOutstanding,
            'aging' => $aging,
            'commission' => [
                'monthly' => $monthlyCommission,
                'total' => $totalCommission,
            ],
            'payouts' => [
                'pending' => $pendingPayouts,
                'completed' => $completedPayouts,
            ],
            'orders' => [
                'monthly' => $monthlyOrders,
                'pending' => $pendingOrders,
            ],
        ];
    }

    /**
     * Get aging report for accounts receivable
     */
    public function getAgingReport(): array
    {
        $invoices = Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])->get();

        $aging = [
            'current' => 0,
            '1-30' => 0,
            '31-60' => 0,
            '61-90' => 0,
            '90+' => 0,
        ];

        foreach ($invoices as $invoice) {
            $bucket = $invoice->getAgingBucket();
            if (isset($aging[$bucket])) {
                $aging[$bucket] += $invoice->balance_due;
            }
        }

        return $aging;
    }

    /**
     * Get supplier earnings report
     */
    public function getSupplierEarningsReport(Supplier $supplier, ?string $startDate = null, ?string $endDate = null): array
    {
        $query = SupplierTransaction::where('supplier_id', $supplier->id);

        if ($startDate) {
            $query->where('created_at', '>=', $startDate);
        }
        if ($endDate) {
            $query->where('created_at', '<=', $endDate);
        }

        $transactions = $query->get();

        return [
            'total_sales' => $transactions->where('type', 'sale')->sum('amount'),
            'total_commission' => $transactions->where('type', 'sale')->sum('commission_amount'),
            'net_earnings' => $transactions->where('type', 'sale')->sum('net_amount'),
            'pending_payout' => $transactions->where('status', 'pending')->sum('net_amount'),
            'paid_out' => $transactions->where('status', 'paid')->sum('net_amount'),
            'transaction_count' => $transactions->count(),
        ];
    }

    /**
     * Get profit and loss summary
     */
    public function getProfitLossSummary(?string $startDate = null, ?string $endDate = null): array
    {
        $query = LedgerEntry::query();

        if ($startDate) {
            $query->where('created_at', '>=', $startDate);
        }
        if ($endDate) {
            $query->where('created_at', '<=', $endDate);
        }

        $entries = $query->get();

        $income = $entries->where('direction', 'credit')->sum('amount');
        $expenses = $entries->where('direction', 'debit')->sum('amount');

        $byCategory = $entries->groupBy('category')->map(function ($items, $category) {
            return [
                'category' => $category,
                'credit' => $items->where('direction', 'credit')->sum('amount'),
                'debit' => $items->where('direction', 'debit')->sum('amount'),
            ];
        })->values();

        return [
            'total_income' => $income,
            'total_expenses' => $expenses,
            'net_profit' => $income - $expenses,
            'by_category' => $byCategory,
        ];
    }

    /**
     * Update overdue invoices
     */
    public function updateOverdueInvoices(): int
    {
        return Invoice::whereIn('status', ['sent', 'partially_paid'])
            ->where('due_date', '<', now())
            ->update(['status' => 'overdue']);
    }
}
