<?php

namespace App\Filament\Pages;

use Carbon\Carbon;
use App\Models\Sale;
use App\Models\Product;
use App\Models\Purchase;
use Filament\Pages\Page;
use App\Models\Warehouse;
use App\Models\SaleReturn;
use App\Models\ProductUnit;
use Filament\Schemas\Schema;
use App\Models\OpeningBalance;
use App\Models\PurchaseReturn;
use Illuminate\Contracts\View\View;
use Filament\Forms\Components\Select;
use Filament\Forms\Contracts\HasForms;
use Filament\Schemas\Components\Section;
use Filament\Forms\Components\DatePicker;
use App\Exports\ItemMovementExport;
use Maatwebsite\Excel\Facades\Excel;
use Mpdf\Mpdf;
use Filament\Forms\Concerns\InteractsWithForms;

class ItemMovementReport extends Page implements HasForms
{
    use InteractsWithForms;

    protected string $view = 'filament.pages.item-movement-report';

    public ?array $data = [];
    public array $report_data = [];

    public ?string $movement_type = null;

    protected static string|\UnitEnum|null $navigationGroup = 'products';

    protected static ?int $navigationSort = 8;

    public function getTitle(): string
    {
        return __('filament/admin/reports.item_movement');
    }

    public static function getNavigationLabel(): string
    {
        return __('filament/admin/reports.item_movement');
    }

    public static function getNavigationGroup(): ?string
    {
        return __('filament.navigation_groups.products');
    }

    public function mount(): void
    {
        $this->form->fill([
            'from_date' => now()->startOfMonth(),
            'to_date' => now()->endOfMonth(),
            'compare_from_date' => null,
            'compare_to_date' => null,
            'movement_type' => null,
        ]);
    }

    public function form(Schema $schema): Schema
    {
        return $schema
            ->statePath('data')
            ->components([
                Section::make(__('filament/admin/reports.filters'))
                    ->columns(4)
                    ->schema([
                        Select::make('product_id')
                            ->label(__('filament/admin/reports.product'))
                            ->placeholder(__('filament/admin/reports.select_product'))
                            ->options(Product::whereNotNull('name_ar')->pluck('name_ar', 'id'))
                            ->getOptionLabelFromRecordUsing(fn ($record) => $record->name_ar ?? $record->name)
                            ->searchable()
                            ->preload()
                            ->required(),

                        Select::make('warehouse_id')
                            ->label(__('filament/admin/reports.warehouse'))
                            ->placeholder(__('filament/admin/reports.select_warehouse'))
                            ->options(Warehouse::whereNotNull('name_ar')->pluck('name_ar', 'id'))
                            ->getOptionLabelFromRecordUsing(fn ($record) => $record->name_ar ?? $record->name)
                            ->searchable()
                            ->preload()
                            ->required(),

                        DatePicker::make('from_date')
                            ->label(__('filament/admin/reports.from_date'))
                            ->native(false),

                        DatePicker::make('to_date')
                            ->label(__('filament/admin/reports.to_date'))
                            ->native(false),

                        Select::make('movement_type')
                            ->label(__('filament/admin/reports.operation_type'))
                            ->placeholder(__('filament/admin/reports.any'))
                            ->options([
                                'purchase' => __('filament/admin/reports.purchase'),
                                'sale' => __('filament/admin/reports.sale'),
                                'sale_return' => __('filament/admin/reports.sale_return'),
                                'purchase_return' => __('filament/admin/reports.purchase_return'),
                            ])
                            ->native(false)
                            ->searchable(),

                        DatePicker::make('compare_from_date')
                            ->label(__('filament/admin/reports.compare_from_date'))
                            ->native(false),

                        DatePicker::make('compare_to_date')
                            ->label(__('filament/admin/reports.compare_to_date'))
                            ->native(false),
                    ]),
            ]);
    }

    public function generateReport(): void
    {
        $product_id = $this->data['product_id'] ?? null;
        $warehouse_id = $this->data['warehouse_id'] ?? null;
        
        if (!$product_id || !$warehouse_id) {
            $this->report_data = [];
            return;
        }

        $product = Product::with(['productUnits.unit', 'baseUnit'])->findOrFail($product_id);
        $warehouse = Warehouse::findOrFail($warehouse_id);
        $from_date = isset($this->data['from_date']) ? Carbon::parse($this->data['from_date'])->startOfDay() : null;
        $to_date = isset($this->data['to_date']) ? Carbon::parse($this->data['to_date'])->endOfDay() : Carbon::now()->endOfDay();
        $movementType = $this->data['movement_type'] ?? null;

        // حساب الرصيد الافتتاحي (قبل تاريخ البداية)
        $opening_balance = $this->calculateOpeningBalance($product, $warehouse, $from_date);

        // جلب جميع الحركات في الفترة المحددة
        $movements = $this->getMovements($product, $warehouse, $from_date, $to_date, $movementType);

        $summary = $this->summarizeMovements($movements, $opening_balance);

        // مقارنة بفترة أخرى إن وُجدت
        $compare = null;
        if (!empty($this->data['compare_from_date']) && !empty($this->data['compare_to_date'])) {
            $compareFrom = Carbon::parse($this->data['compare_from_date'])->startOfDay();
            $compareTo = Carbon::parse($this->data['compare_to_date'])->endOfDay();
            $compareMovements = $this->getMovements($product, $warehouse, $compareFrom, $compareTo, $movementType);
            $compare = $this->summarizeMovements($compareMovements, $this->calculateOpeningBalance($product, $warehouse, $compareFrom));
        }

        // حساب الرصيد الختامي
        $closing_balance = $summary['closing_balance'];

        $this->report_data = [
            'product' => $product,
            'warehouse' => $warehouse,
            'from_date' => $from_date?->format('Y-m-d'),
            'to_date' => $to_date->format('Y-m-d'),
            'opening_balance' => $opening_balance,
            'opening_balance_display' => $this->formatQuantityInUnits($opening_balance, $product),
            'closing_balance' => $closing_balance,
            'closing_balance_display' => $this->formatQuantityInUnits($closing_balance, $product),
            'movements' => $movements,
            'summary' => $summary,
            'compare' => $compare,
            'movement_type' => $movementType,
        ];
    }

    /**
     * حساب الرصيد الافتتاحي قبل التاريخ المحدد
     */
    private function calculateOpeningBalance(Product $product, Warehouse $warehouse, ?Carbon $from_date): float
    {
        // 1. الرصيد الافتتاحي الأساسي للصنف
        $basicOpeningBalance = OpeningBalance::where('product_id', $product->id)
            ->where('warehouse_id', $warehouse->id)
            ->sum('quantity') ?? 0;

        // دالة لتحويل الكمية إلى الوحدة الأساسية
        $convertToBase = function ($quantity, $unitId) use ($product) {
            if (!$unitId || $quantity == 0) {
                return 0;
            }
            
            $productUnit = $product->productUnits->firstWhere('unit_id', $unitId);
            if (!$productUnit) {
                return $quantity;
            }
            
            return $quantity * ($productUnit->conversion_factor ?? 1);
        };

        // 2. المشتريات قبل التاريخ
        $purchases = \App\Models\PurchaseItem::whereHas('purchase', function ($q) use ($warehouse, $from_date) {
            $q->where('warehouse_id', $warehouse->id);
            if ($from_date) {
                $q->where('created_at', '<', $from_date);
            }
        })->where('product_id', $product->id)->get();

        $purchasesTotal = 0;
        foreach ($purchases as $item) {
            $purchasesTotal += $convertToBase($item->quantity, $item->unit_id);
        }

        // 3. المبيعات قبل التاريخ
        $sales = \App\Models\SaleItem::whereHas('sale', function ($q) use ($warehouse, $from_date) {
            $q->where('warehouse_id', $warehouse->id);
            if ($from_date) {
                $q->where('created_at', '<', $from_date);
            }
        })->where('product_id', $product->id)->get();

        $salesTotal = 0;
        foreach ($sales as $item) {
            $salesTotal += $convertToBase($item->quantity, $item->unit_id);
        }

        // 4. مرتجع عميل قبل التاريخ (يضاف)
        $saleReturns = \App\Models\SaleReturnItem::whereHas('saleReturn', function ($q) use ($warehouse, $from_date) {
            $q->where('warehouse_id', $warehouse->id);
            if ($from_date) {
                $q->where('created_at', '<', $from_date);
            }
        })->where('product_id', $product->id)->get();

        $saleReturnsTotal = 0;
        foreach ($saleReturns as $item) {
            $saleReturnsTotal += $convertToBase($item->quantity, $item->unit_id);
        }

        // 5. مرتجع لمورد قبل التاريخ (يطرح)
        $purchaseReturns = \App\Models\PurchaseReturnItem::whereHas('purchaseReturn', function ($q) use ($warehouse, $from_date) {
            $q->where('warehouse_id', $warehouse->id);
            if ($from_date) {
                $q->where('created_at', '<', $from_date);
            }
        })->where('product_id', $product->id)->get();

        $purchaseReturnsTotal = 0;
        foreach ($purchaseReturns as $item) {
            $purchaseReturnsTotal += $convertToBase($item->quantity, $item->unit_id);
        }

        // الرصيد الافتتاحي = الرصيد الأساسي + المشتريات + مرتجع العملاء - المبيعات - مرتجع الموردين
        return $basicOpeningBalance + $purchasesTotal + $saleReturnsTotal - $salesTotal - $purchaseReturnsTotal;
    }

    /**
     * جلب جميع الحركات في الفترة المحددة
     */
    private function getMovements(Product $product, Warehouse $warehouse, ?Carbon $from_date, Carbon $to_date, ?string $movementType = null): \Illuminate\Support\Collection
    {
        $movements = collect();

        // دالة لتحويل الكمية إلى الوحدة الأساسية
        $convertToBase = function ($quantity, $unitId) use ($product) {
            if (!$unitId || $quantity == 0) {
                return 0;
            }
            
            $productUnit = $product->productUnits->firstWhere('unit_id', $unitId);
            if (!$productUnit) {
                return $quantity;
            }
            
            return $quantity * ($productUnit->conversion_factor ?? 1);
        };

        // 1. المشتريات
        $purchases = \App\Models\PurchaseItem::with(['purchase', 'unit'])
            ->whereHas('purchase', function ($q) use ($warehouse, $from_date, $to_date) {
                $q->where('warehouse_id', $warehouse->id);
                if ($from_date) {
                    $q->where('created_at', '>=', $from_date);
                }
                $q->where('created_at', '<=', $to_date);
            })
            ->where('product_id', $product->id)
            ->get();

        foreach ($purchases as $item) {
            $movements->push([
                'date' => $item->purchase->created_at->format('Y-m-d H:i:s'),
                'type' => 'purchase',
                'reference_number' => $item->purchase->id,
                'description' => __('filament/admin/reports.purchase_invoice'),
                'quantity' => $item->quantity,
                'unit_name' => $item->unit->name_ar ?? '',
                'quantity_change' => $convertToBase($item->quantity, $item->unit_id), // إيجابي
                'sort_date' => $item->purchase->created_at,
            ]);
        }

        // 2. المبيعات
        $sales = \App\Models\SaleItem::with(['sale', 'unit'])
            ->whereHas('sale', function ($q) use ($warehouse, $from_date, $to_date) {
                $q->where('warehouse_id', $warehouse->id);
                if ($from_date) {
                    $q->where('created_at', '>=', $from_date);
                }
                $q->where('created_at', '<=', $to_date);
            })
            ->where('product_id', $product->id)
            ->get();

        foreach ($sales as $item) {
            $movements->push([
                'date' => $item->sale->created_at->format('Y-m-d H:i:s'),
                'type' => 'sale',
                'reference_number' => $item->sale->id,
                'description' => __('filament/admin/reports.sale_invoice'),
                'quantity' => $item->quantity,
                'unit_name' => $item->unit->name_ar ?? '',
                'quantity_change' => -$convertToBase($item->quantity, $item->unit_id), // سالب
                'sort_date' => $item->sale->created_at,
            ]);
        }

        // 3. مرتجع عميل (يضاف للمخزون)
        $saleReturns = \App\Models\SaleReturnItem::with(['saleReturn', 'unit'])
            ->whereHas('saleReturn', function ($q) use ($warehouse, $from_date, $to_date) {
                $q->where('warehouse_id', $warehouse->id);
                if ($from_date) {
                    $q->where('created_at', '>=', $from_date);
                }
                $q->where('created_at', '<=', $to_date);
            })
            ->where('product_id', $product->id)
            ->get();

        foreach ($saleReturns as $item) {
            $movements->push([
                'date' => $item->saleReturn->created_at->format('Y-m-d H:i:s'),
                'type' => 'sale_return',
                'reference_number' => $item->saleReturn->id,
                'description' => __('filament/admin/reports.customer_return'),
                'quantity' => $item->quantity,
                'unit_name' => $item->unit->name_ar ?? '',
                'quantity_change' => $convertToBase($item->quantity, $item->unit_id), // إيجابي
                'sort_date' => $item->saleReturn->created_at,
            ]);
        }

        // 4. مرتجع لمورد (يطرح من المخزون)
        $purchaseReturns = \App\Models\PurchaseReturnItem::with(['purchaseReturn', 'unit'])
            ->whereHas('purchaseReturn', function ($q) use ($warehouse, $from_date, $to_date) {
                $q->where('warehouse_id', $warehouse->id);
                if ($from_date) {
                    $q->where('created_at', '>=', $from_date);
                }
                $q->where('created_at', '<=', $to_date);
            })
            ->where('product_id', $product->id)
            ->get();

        foreach ($purchaseReturns as $item) {
            $movements->push([
                'date' => $item->purchaseReturn->created_at->format('Y-m-d H:i:s'),
                'type' => 'purchase_return',
                'reference_number' => $item->purchaseReturn->id,
                'description' => __('filament/admin/reports.supplier_return'),
                'quantity' => $item->quantity,
                'unit_name' => $item->unit->name_ar ?? '',
                'quantity_change' => -$convertToBase($item->quantity, $item->unit_id), // سالب
                'sort_date' => $item->purchaseReturn->created_at,
            ]);
        }

        // ترتيب الحركات حسب التاريخ
        $movements = $movements->sortBy('sort_date')->values();

        if ($movementType) {
            $movements = $movements->where('type', $movementType)->values();
        }

        return $movements;
    }

    /**
     * تحويل الكمية إلى وحدات كبرى وصغرى
     */
    private function formatQuantityInUnits(float $baseQuantity, Product $product): string
    {
        if ($baseQuantity <= 0) {
            return '0';
        }

        // جلب جميع الوحدات مرتبة من الأكبر للأصغر
        $units = $product->productUnits()
            ->with('unit')
            ->orderBy('conversion_factor', 'desc')
            ->get();

        if ($units->isEmpty()) {
            return number_format($baseQuantity, 2);
        }

        $remainingQuantity = $baseQuantity;
        $parts = [];

        foreach ($units as $productUnit) {
            $conversionFactor = $productUnit->conversion_factor ?? 1;
            
            if ($conversionFactor > 1 && $remainingQuantity >= $conversionFactor) {
                $unitsCount = floor($remainingQuantity / $conversionFactor);
                $parts[] = $unitsCount . ' ' . ($productUnit->unit->name_ar ?? $productUnit->unit->name);
                $remainingQuantity = $remainingQuantity - ($unitsCount * $conversionFactor);
            }
        }

        // إضافة الوحدة الأصغر (الأساسية) إن وجدت
        if ($remainingQuantity > 0) {
            $baseUnit = $product->baseUnit;
            $parts[] = $remainingQuantity . ' ' . ($baseUnit->name_ar ?? $baseUnit->name);
        }

        return implode(' + ', $parts);
    }

    private function summarizeMovements(\Illuminate\Support\Collection $movements, float $opening): array
    {
        $totalIn = $movements->where('quantity_change', '>', 0)->sum('quantity_change');
        $totalOut = abs($movements->where('quantity_change', '<', 0)->sum('quantity_change'));
        $net = $movements->sum('quantity_change');

        return [
            'total_in' => $totalIn,
            'total_out' => $totalOut,
            'net_change' => $net,
            'closing_balance' => $opening + $net,
        ];
    }

    public function exportExcel()
    {
        if (empty($this->report_data)) {
            $this->generateReport();
        }

        $product = Product::find($this->data['product_id']);

        return Excel::download(
            new ItemMovementExport($this->report_data, $product, $this->data['from_date'], $this->data['to_date']),
            'item-movement-' . $product->name_ar . '-' . now()->format('Y-m-d') . '.xlsx'
        );
    }

    public function exportPdf()
    {
        if (empty($this->report_data)) {
            $this->generateReport();
        }

        $product = Product::find($this->data['product_id']);

        $mpdf = new Mpdf([
            'mode' => 'utf-8',
            'format' => 'A4',
            'orientation' => 'L',
            'default_font' => 'dejavusans',
            'autoScriptToLang' => true,
            'autoLangToFont' => true,
        ]);

        $mpdf->SetDirectionality('rtl');

        $html = view('reports.pdf.item-movement', [
            'data' => $this->report_data,
            'product' => $product,
            'from_date' => $this->data['from_date'],
            'to_date' => $this->data['to_date'],
        ])->render();

        $mpdf->WriteHTML($html);

        return response()->streamDownload(function () use ($mpdf) {
            echo $mpdf->Output('', 'S');
        }, 'item-movement-' . $product->name_ar . '-' . now()->format('Y-m-d') . '.pdf');
    }

    public static function shouldRegisterNavigation(): bool
    {
        return true;
    }
}
