<?php

namespace App\Core\Services\Estimate;

use App\Core\Repositories\CustomerRepository;
use App\Models\Estimate;
use App\Models\EstimateItem;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Estimate Service
 * Handles estimate business logic
 */
class EstimateService
{
    public function __construct(
        private CustomerRepository $customerRepository
    ) {}

    /**
     * Create a new estimate
     */
    public function create(array $data): Estimate
    {
        DB::beginTransaction();

        try {
            // Generate estimate number
            $data['estimate_number'] = $this->generateEstimateNumber();

            // Calculate totals
            $totals = $this->calculateTotals(
                $data['items'] ?? [],
                $data['discount_amount'] ?? null,
                $data['discount_type'] ?? null
            );

            // Create estimate
            $estimate = Estimate::create([
                'estimate_number' => $data['estimate_number'],
                'customer_id' => $data['customer_id'],
                'issue_date' => $data['issue_date'],
                'expiry_date' => $data['expiry_date'],
                'status' => $data['status'] ?? 'draft',
                'subtotal' => $totals['subtotal'],
                'tax_amount' => $totals['tax_amount'],
                'discount_amount' => $totals['discount_amount'] ?? 0,
                'discount_type' => $data['discount_type'] ?? null,
                'total' => $totals['total'],
                'currency' => $data['currency'] ?? \App\Models\Currency::getDefaultCode(),
                'notes' => $data['notes'] ?? null,
                'terms' => $data['terms'] ?? null,
                'created_by' => auth()->id(),
            ]);

            // Create estimate items
            if (isset($data['items']) && is_array($data['items'])) {
                $this->createEstimateItems($estimate, $data['items']);
            }

            DB::commit();

            return $estimate->load(['customer', 'items']);
        } catch (Exception $e) {
            DB::rollBack();
            Log::error('Estimate creation failed: '.$e->getMessage());
            throw $e;
        }
    }

    /**
     * Update an estimate
     */
    public function update(Estimate $estimate, array $data): Estimate
    {
        DB::beginTransaction();

        try {
            // Calculate totals
            $totals = $this->calculateTotals(
                $data['items'] ?? [],
                $data['discount_amount'] ?? null,
                $data['discount_type'] ?? null
            );

            // Update estimate
            $estimate->update([
                'customer_id' => $data['customer_id'] ?? $estimate->customer_id,
                'issue_date' => $data['issue_date'] ?? $estimate->issue_date,
                'expiry_date' => $data['expiry_date'] ?? $estimate->expiry_date,
                'status' => $data['status'] ?? $estimate->status,
                'subtotal' => $totals['subtotal'],
                'tax_amount' => $totals['tax_amount'],
                'discount_amount' => $totals['discount_amount'] ?? 0,
                'discount_type' => $data['discount_type'] ?? $estimate->discount_type,
                'total' => $totals['total'],
                'currency' => $data['currency'] ?? $estimate->currency,
                'notes' => $data['notes'] ?? $estimate->notes,
                'terms' => $data['terms'] ?? $estimate->terms,
            ]);

            // Update items
            if (isset($data['items']) && is_array($data['items'])) {
                $estimate->items()->delete();
                $this->createEstimateItems($estimate, $data['items']);
            }

            DB::commit();

            return $estimate->fresh(['customer', 'items']);
        } catch (Exception $e) {
            DB::rollBack();
            Log::error('Estimate update failed: '.$e->getMessage());
            throw $e;
        }
    }

    /**
     * Convert estimate to invoice
     */
    public function convertToInvoice(Estimate $estimate): \App\Models\Invoice
    {
        $invoiceService = app(\App\Core\Services\Invoice\InvoiceService::class);

        $invoiceData = [
            'customer_id' => $estimate->customer_id,
            'issue_date' => now(),
            'due_date' => now()->addDays(30),
            'status' => 'draft',
            'currency' => $estimate->currency,
            'notes' => $estimate->notes,
            'terms' => $estimate->terms,
            'items' => $estimate->items->map(function ($item) {
                return [
                    'description' => $item->description,
                    'quantity' => $item->quantity,
                    'unit_price' => $item->unit_price,
                    'tax_rate' => $item->tax_rate,
                ];
            })->toArray(),
        ];

        $invoice = $invoiceService->create($invoiceData);

        // Mark estimate as accepted
        $estimate->update([
            'status' => 'accepted',
            'accepted_at' => now(),
        ]);

        return $invoice;
    }

    /**
     * Create estimate items
     */
    private function createEstimateItems(Estimate $estimate, array $items): void
    {
        foreach ($items as $index => $item) {
            $subtotal = $item['quantity'] * $item['unit_price'];
            $taxAmount = $subtotal * ($item['tax_rate'] ?? 0) / 100;
            $total = $subtotal + $taxAmount;

            EstimateItem::create([
                'estimate_id' => $estimate->id,
                'description' => $item['description'],
                'quantity' => $item['quantity'],
                'unit_price' => $item['unit_price'],
                'tax_rate' => $item['tax_rate'] ?? 0,
                'tax_amount' => $taxAmount,
                'total' => $total,
                'sort_order' => $index,
            ]);
        }
    }

    /**
     * Calculate estimate totals
     */
    private function calculateTotals(array $items, ?float $discountAmount = null, ?string $discountType = null): array
    {
        $subtotal = 0;
        $taxAmount = 0;

        foreach ($items as $item) {
            $itemSubtotal = $item['quantity'] * $item['unit_price'];
            $itemTax = $itemSubtotal * ($item['tax_rate'] ?? 0) / 100;

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

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

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

        return [
            'subtotal' => $subtotal,
            'tax_amount' => $taxAmount,
            'discount_amount' => $discount,
            'total' => max(0, $total),
        ];
    }

    /**
     * Generate estimate number
     */
    private function generateEstimateNumber(): string
    {
        $prefix = config('invoice.estimate_prefix', 'EST');
        $year = now()->year;
        $lastEstimate = Estimate::whereYear('created_at', $year)
            ->orderBy('id', 'desc')
            ->first();

        if ($lastEstimate) {
            $lastNumber = (int) substr($lastEstimate->estimate_number, -6);
            $nextNumber = $lastNumber + 1;
        } else {
            $nextNumber = 1;
        }

        return $prefix.'-'.$year.'-'.str_pad($nextNumber, 6, '0', STR_PAD_LEFT);
    }
}
