<?php

namespace App\Services;

use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\MaintenanceContract;
use App\Models\MaintenanceSchedule;
use App\Models\Company;
use App\Models\Notification;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class AutoInvoiceService
{
    /**
     * Generate invoices automatically from maintenance contracts
     * 
     * @return array Statistics about generated invoices
     */
    public function generateContractInvoices($companyId = null)
    {
        $stats = [
            'total' => 0,
            'success' => 0,
            'failed' => 0,
            'companies' => []
        ];

        try {
            // Get active contracts that need invoicing
            $query = MaintenanceContract::where('status', 'active');
            
            if ($companyId) {
                $query->where('company_id', $companyId);
            }

            $contracts = $query->where(function ($query) {
                    // Contract has no invoices yet
                    $query->whereDoesntHave('invoices')
                        // OR last invoice was generated according to billing cycle
                        ->orWhereHas('invoices', function ($q) {
                            $q->where(function ($subq) {
                                // Monthly contracts - last invoice more than 1 month ago
                                $subq->where('billing_cycle', 'monthly')
                                    ->whereDate('invoice_date', '<=', Carbon::now()->subMonth());
                            })->orWhere(function ($subq) {
                                // Quarterly contracts - last invoice more than 3 months ago
                                $subq->where('billing_cycle', 'quarterly')
                                    ->whereDate('invoice_date', '<=', Carbon::now()->subMonths(3));
                            })->orWhere(function ($subq) {
                                // Semi-annual contracts - last invoice more than 6 months ago
                                $subq->where('billing_cycle', 'semi_annually')
                                    ->whereDate('invoice_date', '<=', Carbon::now()->subMonths(6));
                            })->orWhere(function ($subq) {
                                // Annual contracts - last invoice more than 12 months ago
                                $subq->where('billing_cycle', 'annually')
                                    ->whereDate('invoice_date', '<=', Carbon::now()->subYear());
                            });
                        });
                })
                ->with(['customer', 'company', 'elevators'])
                ->get();

            $stats['total'] = $contracts->count();

            foreach ($contracts as $contract) {
                try {
                    DB::beginTransaction();

                    // Get company
                    $company = $contract->company;

                    if (!isset($stats['companies'][$company->id])) {
                        $stats['companies'][$company->id] = [
                            'name' => $company->name,
                            'success' => 0,
                            'failed' => 0
                        ];
                    }

                    // Create invoice
                    $invoice = $this->createInvoiceFromContract($contract);

                    // Create notification
                    Notification::create([
                        'company_id' => $company->id,
                        'user_id' => null, // Company-wide notification
                        'type' => 'invoice_generated',
                        'notifiable_type' => 'App\Models\Invoice',
                        'notifiable_id' => $invoice->id,
                        'title' => 'تم إنشاء فاتورة جديدة',
                        'message' => 'تم إنشاء فاتورة جديدة تلقائياً للعقد رقم ' . $contract->contract_number,
                        'data' => json_encode([
                            'invoice_id' => $invoice->id,
                            'invoice_number' => $invoice->invoice_number,
                            'contract_id' => $contract->id,
                            'contract_number' => $contract->contract_number,
                            'customer_id' => $contract->customer_id,
                            'customer_name' => $contract->customer->name,
                            'amount' => $invoice->total_amount
                        ]),
                        'status' => 'pending',
                        'priority' => 'normal',
                    ]);

                    DB::commit();
                    $stats['success']++;
                    $stats['companies'][$company->id]['success']++;
                } catch (\Exception $e) {
                    DB::rollBack();
                    Log::error('Failed to generate invoice for contract #' . $contract->id . ': ' . $e->getMessage());
                    $stats['failed']++;
                    $stats['companies'][$company->id]['failed']++;
                }
            }
        } catch (\Exception $e) {
            Log::error('Error in auto invoice generation: ' . $e->getMessage());
        }

        return $stats;
    }

    /**
     * Generate invoices from completed maintenance schedules
     * 
     * @return array Statistics about generated invoices
     */
    public function generateMaintenanceInvoices($companyId = null)
    {
        $stats = [
            'total' => 0,
            'success' => 0,
            'failed' => 0,
            'companies' => []
        ];

        try {
            // Get completed maintenance schedules that don't have invoices yet
            $query = MaintenanceSchedule::where('status', 'completed')
                ->whereDoesntHave('invoice');

            if ($companyId) {
                $query->where('company_id', $companyId);
            }

            $schedules = $query->with(['elevator', 'maintenanceContract', 'maintenanceLogs', 'company'])
                ->get();

            $stats['total'] = $schedules->count();

            // Group schedules by company and contract
            $groupedSchedules = $schedules->groupBy(['company_id', 'maintenance_contract_id']);

            foreach ($groupedSchedules as $companyId => $companySchedules) {
                $company = Company::find($companyId);

                if (!isset($stats['companies'][$companyId])) {
                    $stats['companies'][$companyId] = [
                        'name' => $company->name,
                        'success' => 0,
                        'failed' => 0
                    ];
                }

                foreach ($companySchedules as $contractId => $contractSchedules) {
                    if (empty($contractId)) continue; // Skip if no contract

                    try {
                        DB::beginTransaction();

                        $contract = MaintenanceContract::find($contractId);
                        if (!$contract) continue;

                        // Create invoice for this batch of schedules
                        $invoice = $this->createInvoiceFromMaintenanceSchedules($contractSchedules, $contract);

                        // Update schedules to link them to the invoice
                        foreach ($contractSchedules as $schedule) {
                            $schedule->invoice_id = $invoice->id;
                            $schedule->save();
                        }

                        // Create notification
                        Notification::create([
                            'company_id' => $companyId,
                            'user_id' => null, // Company-wide notification
                            'type' => 'maintenance_invoice_generated',
                            'notifiable_type' => 'App\Models\Invoice',
                            'notifiable_id' => $invoice->id,
                            'title' => 'تم إنشاء فاتورة صيانة جديدة',
                            'message' => 'تم إنشاء فاتورة جديدة تلقائياً لـ ' . $contractSchedules->count() . ' عمليات صيانة مكتملة',
                            'data' => json_encode([
                                'invoice_id' => $invoice->id,
                                'invoice_number' => $invoice->invoice_number,
                                'contract_id' => $contract->id,
                                'contract_number' => $contract->contract_number,
                                'customer_id' => $contract->customer_id,
                                'customer_name' => $contract->customer->name,
                                'amount' => $invoice->total_amount,
                                'schedules_count' => $contractSchedules->count()
                            ]),
                            'status' => 'pending',
                            'priority' => 'normal',
                        ]);

                        DB::commit();
                        $stats['success']++;
                        $stats['companies'][$companyId]['success']++;
                    } catch (\Exception $e) {
                        DB::rollBack();
                        Log::error('Failed to generate invoice for maintenance schedules: ' . $e->getMessage());
                        $stats['failed']++;
                        $stats['companies'][$companyId]['failed']++;
                    }
                }
            }
        } catch (\Exception $e) {
            Log::error('Error in maintenance invoice generation: ' . $e->getMessage());
        }

        return $stats;
    }

    /**
     * Create an invoice from a maintenance contract
     * 
     * @param MaintenanceContract $contract
     * @return Invoice
     */
    protected function createInvoiceFromContract(MaintenanceContract $contract)
    {
        $company = $contract->company;
        $customer = $contract->customer;

        // Get default template if available
        $template = $company->invoiceTemplates()
            ->where('is_default', true)
            ->where('is_active', true)
            ->first();

        // Generate invoice number
        $invoiceNumber = 'INV-' . $company->id . '-' . date('Ymd') . '-' . rand(1000, 9999);

        // Calculate dates
        $invoiceDate = Carbon::now();
        $dueDate = Carbon::now()->addDays(30); // Default 30 days due date

        // Calculate amounts
        $subtotal = $contract->amount;
        $taxRate = 15.00; // Default VAT rate
        $taxAmount = $subtotal * ($taxRate / 100);
        $totalAmount = $subtotal + $taxAmount;

        // Create invoice
        $invoice = Invoice::create([
            'company_id' => $company->id,
            'customer_id' => $customer->id,
            'maintenance_contract_id' => $contract->id,
            'branch_id' => $company->branches->first()->id ?? null,
            'created_by' => null, // System generated
            'template_id' => $template->id ?? null,
            'invoice_number' => $invoiceNumber,
            'invoice_date' => $invoiceDate,
            'due_date' => $dueDate,
            'subtotal' => $subtotal,
            'tax_rate' => $taxRate,
            'tax_amount' => $taxAmount,
            'discount_percentage' => 0,
            'discount_amount' => 0,
            'total_amount' => $totalAmount,
            'paid_amount' => 0,
            'due_amount' => $totalAmount,
            'status' => 'sent',
            'notes' => 'تم إنشاء هذه الفاتورة تلقائياً من عقد الصيانة رقم ' . $contract->contract_number,
            'terms_conditions' => $company->invoice_terms ?? null,
            'language' => $company->default_language ?? 'ar',
            'is_recurring' => true,
            'recurring_cycle' => $contract->billing_cycle,
            'next_recurring_date' => $this->calculateNextRecurringDate($invoiceDate, $contract->billing_cycle),
        ]);

        // Create invoice item
        InvoiceItem::create([
            'invoice_id' => $invoice->id,
            'description' => 'خدمة صيانة دورية - عقد رقم ' . $contract->contract_number,
            'quantity' => 1,
            'unit_price' => $subtotal,
            'discount_percentage' => 0,
            'discount_amount' => 0,
            'tax_percentage' => $taxRate,
            'tax_amount' => $taxAmount,
            'subtotal' => $subtotal,
            'total' => $totalAmount,
        ]);

        return $invoice;
    }

    /**
     * Create an invoice from maintenance schedules
     * 
     * @param \Illuminate\Support\Collection $schedules
     * @param MaintenanceContract $contract
     * @return Invoice
     */
    protected function createInvoiceFromMaintenanceSchedules($schedules, MaintenanceContract $contract)
    {
        $company = $contract->company;
        $customer = $contract->customer;

        // Get default template if available
        $template = $company->invoiceTemplates()
            ->where('is_default', true)
            ->where('is_active', true)
            ->first();

        // Generate invoice number
        $invoiceNumber = 'INV-M-' . $company->id . '-' . date('Ymd') . '-' . rand(1000, 9999);

        // Calculate dates
        $invoiceDate = Carbon::now();
        $dueDate = Carbon::now()->addDays(30); // Default 30 days due date

        // Calculate amounts based on contract or fixed maintenance fee
        $maintenanceFee = $contract->maintenance_fee ?? 200; // Default fee if not specified
        $subtotal = $maintenanceFee * $schedules->count();
        $taxRate = 15.00; // Default VAT rate
        $taxAmount = $subtotal * ($taxRate / 100);
        $totalAmount = $subtotal + $taxAmount;

        // Create invoice
        $invoice = Invoice::create([
            'company_id' => $company->id,
            'customer_id' => $customer->id,
            'maintenance_contract_id' => $contract->id,
            'branch_id' => $company->branches->first()->id ?? null,
            'created_by' => null, // System generated
            'template_id' => $template->id ?? null,
            'invoice_number' => $invoiceNumber,
            'invoice_date' => $invoiceDate,
            'due_date' => $dueDate,
            'subtotal' => $subtotal,
            'tax_rate' => $taxRate,
            'tax_amount' => $taxAmount,
            'discount_percentage' => 0,
            'discount_amount' => 0,
            'total_amount' => $totalAmount,
            'paid_amount' => 0,
            'due_amount' => $totalAmount,
            'status' => 'sent',
            'notes' => 'تم إنشاء هذه الفاتورة تلقائياً لعدد ' . $schedules->count() . ' عمليات صيانة مكتملة',
            'terms_conditions' => $company->invoice_terms ?? null,
            'language' => $company->default_language ?? 'ar',
            'is_recurring' => false,
        ]);

        // Create invoice items for each maintenance schedule
        foreach ($schedules as $schedule) {
            $elevator = $schedule->elevator;
            $maintenanceDate = Carbon::parse($schedule->scheduled_date)->format('Y-m-d');

            InvoiceItem::create([
                'invoice_id' => $invoice->id,
                'description' => 'خدمة صيانة للمصعد ' . $elevator->model . ' (الرقم التسلسلي: ' . $elevator->serial_number . ') بتاريخ ' . $maintenanceDate,
                'quantity' => 1,
                'unit_price' => $maintenanceFee,
                'discount_percentage' => 0,
                'discount_amount' => 0,
                'tax_percentage' => $taxRate,
                'tax_amount' => $maintenanceFee * ($taxRate / 100),
                'subtotal' => $maintenanceFee,
                'total' => $maintenanceFee + ($maintenanceFee * ($taxRate / 100)),
            ]);
        }

        return $invoice;
    }

    /**
     * Calculate the next recurring date based on billing cycle
     * 
     * @param \Carbon\Carbon $currentDate
     * @param string $billingCycle
     * @return \Carbon\Carbon
     */
    protected function calculateNextRecurringDate($currentDate, $billingCycle)
    {
        $date = Carbon::parse($currentDate);

        switch ($billingCycle) {
            case 'monthly':
                return $date->addMonth();
            case 'quarterly':
                return $date->addMonths(3);
            case 'semi_annually':
                return $date->addMonths(6);
            case 'annually':
                return $date->addYear();
            default:
                return $date->addMonth();
        }
    }
}
