<?php

namespace App\Filament\Pages;

use Carbon\Carbon;
use App\Models\Product;
use Filament\Pages\Page;
use App\Models\Warehouse;
use Filament\Schemas\Schema;
use App\Models\OpeningBalance;
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 Filament\Forms\Concerns\InteractsWithForms;
use App\Exports\InventoryValuationExport;
use Maatwebsite\Excel\Facades\Excel;
use Mpdf\Mpdf;
use BezhanSalleh\FilamentShield\Traits\HasPageShield;
use Filament\Support\Icons\Heroicon;

class InventoryValuationReport extends Page implements HasForms
{
    use InteractsWithForms;
    use HasPageShield;

    protected string $view = 'filament.pages.inventory-valuation-report';

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

    protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedCalculator;

    protected static string|\UnitEnum|null $navigationGroup = 'products';
    
    protected static ?int $navigationSort = 10;

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

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

    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(),
        ]);
    }

    public function form(Schema $schema): Schema
    {
        return $schema
            ->statePath('data')
            ->components([
                Section::make(__('filament/admin/reports.filters'))
                    ->columns(3)
                    ->schema([
                        Select::make('warehouse_id')
                            ->label(__('filament/admin/reports.warehouse'))
                            ->placeholder(__('filament/admin/reports.select_warehouse'))
                            ->options(Warehouse::all()->mapWithKeys(fn($warehouse) => [$warehouse->id => $warehouse->name_ar ?? $warehouse->name ?? 'مخزن']))
                            ->searchable()
                            ->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),
                    ]),
            ]);
    }

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

        $warehouse = Warehouse::findOrFail($warehouse_id);
        $from_date = isset($formData['from_date']) ? Carbon::parse($formData['from_date'])->startOfDay() : null;
        $to_date = isset($formData['to_date']) ? Carbon::parse($formData['to_date'])->endOfDay() : Carbon::now()->endOfDay();

        if ($from_date && $to_date->lt($from_date)) {
            \Filament\Notifications\Notification::make()
                ->title('تاريخ النهاية يجب أن يكون بعد أو يساوي تاريخ البداية')
                ->warning()
                ->send();
            $this->report_data = [];
            return;
        }

        $products = Product::with(['productUnits.unit', 'baseUnit'])->get();

        $items_data = [];
        $total_opening_qty = 0;
        $total_closing_qty = 0;
        $total_closing_purchase_value = 0;
        $total_closing_sale_value = 0;
        $total_profit = 0;

        foreach ($products as $product) {
            /** @var Product $product */
            $opening_balance = $this->calculateOpeningBalance($product, $warehouse, $from_date);
            $closing_balance = $this->calculateClosingBalance($product, $warehouse, $from_date, $to_date);

            // الحصول على أسعار الوحدة الأساسية
            $baseUnit = $product->productUnits()->where('is_default_purchase', true)->first();
            $purchase_price = $baseUnit?->purchase_price ?? 0;
            $sale_price = $baseUnit?->selling_price ?? 0;

            // حساب القيم: يجب أن تكون الكمية والسعر نفس الوحدة
            // إذا كانت الكمية بالوحدة الأساسية (الكيلو مثلاً) والسعر بنفس الوحدة
            $closing_purchase_value = ($closing_balance * $purchase_price);
            $closing_sale_value = ($closing_balance * $sale_price);
            $profit = $closing_sale_value - $closing_purchase_value;

            if ($opening_balance > 0 || $closing_balance > 0) {
                $items_data[] = [
                    'product' => $product,
                    'opening_balance' => $opening_balance,
                    'closing_balance' => $closing_balance,
                    'purchase_price' => $purchase_price,
                    'sale_price' => $sale_price,
                    'closing_purchase_value' => $closing_purchase_value,
                    'closing_sale_value' => $closing_sale_value,
                    'profit' => $profit,
                ];

                $total_opening_qty += $opening_balance;
                $total_closing_qty += $closing_balance;
                $total_closing_purchase_value += $closing_purchase_value;
                $total_closing_sale_value += $closing_sale_value;
                $total_profit += $profit;
            }
        }

        $this->report_data = [
            'warehouse' => $warehouse,
            'from_date' => $from_date?->format('Y-m-d'),
            'to_date' => $to_date->format('Y-m-d'),
            'items' => $items_data,
            'totals' => [
                'opening_qty' => $total_opening_qty,
                'closing_qty' => $total_closing_qty,
                'closing_purchase_value' => $total_closing_purchase_value,
                'closing_sale_value' => $total_closing_sale_value,
                'profit' => $total_profit,
            ],
        ];
    }

    private function calculateOpeningBalance(Product $product, Warehouse $warehouse, ?Carbon $from_date): float
    {
        $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);
        };

        $purchases = \App\Models\PurchaseItem::with('product')->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();

        $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();

        $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();

        $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();

        $purchasesTotal = $purchases->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $salesTotal = $sales->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $saleReturnsTotal = $saleReturns->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $purchaseReturnsTotal = $purchaseReturns->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));

        return $basicOpeningBalance + $purchasesTotal + $saleReturnsTotal - $salesTotal - $purchaseReturnsTotal;
    }

    private function calculateClosingBalance(Product $product, Warehouse $warehouse, ?Carbon $from_date, Carbon $to_date): float
    {
        $opening = $this->calculateOpeningBalance($product, $warehouse, $from_date);

        $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);
        };

        $purchases = \App\Models\PurchaseItem::with('product')->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();

        $sales = \App\Models\SaleItem::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();

        $saleReturns = \App\Models\SaleReturnItem::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();

        $purchaseReturns = \App\Models\PurchaseReturnItem::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();

        $purchasesTotal = $purchases->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $salesTotal = $sales->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $saleReturnsTotal = $saleReturns->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));
        $purchaseReturnsTotal = $purchaseReturns->sum(fn($item) => $convertToBase($item->quantity, $item->unit_id));

        return $opening + $purchasesTotal + $saleReturnsTotal - $salesTotal - $purchaseReturnsTotal;
    }

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

        return Excel::download(
            new InventoryValuationExport($this->report_data),
            'inventory-valuation-' . now()->format('Y-m-d') . '.xlsx'
        );
    }

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

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

        $mpdf->SetDirectionality('rtl');

        $html = view('reports.pdf.inventory-valuation', [
            'data' => $this->report_data,
        ])->render();

        $mpdf->WriteHTML($html);

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