<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Report extends Model
{
    use HasFactory;
    use SoftDeletes;

    protected $guarded = [
        'id',
        'created_at',
        'updated_at',
    ];

    protected $casts = [
        'attachments' => 'array',
        'documents' => 'array',
        'metrics' => 'array',
        'data' => 'array',
        'report_at' => 'datetime',
        'next_visit_at' => 'date',
        'total_cost' => 'decimal:0',
        'product_weight' => 'decimal:3',
        'water_temp' => 'decimal:2',
        'water_per_unit_daily' => 'decimal:3',
        'wait_between_meals_hours' => 'decimal:2',
        'create_invoice' => 'boolean',
        'date' => 'date',
    ];

    public const TYPE_GROWTH = 1;
    public const TYPE_HEALTH = 2;
    public const TYPE_RATION = 3;

    public const WORKFLOW_PENDING = 'pending';
    public const WORKFLOW_APPROVED = 'approved';
    public const WORKFLOW_REJECTED = 'rejected';
    public const WORKFLOW_NEEDS_EDIT = 'needs_edit';

    public const UNIT_KG = 'kg';
    public const UNIT_M = 'm';
    public const UNIT_HEAD = 'head';

    public const GROWTH_TYPE_WEIGHING = 'weighing';
    public const GROWTH_TYPE_GROWTH = 'growth';

    public static function growthReportTypes(): array
    {
        return [
            self::GROWTH_TYPE_WEIGHING => 'وزن‌کشی',
            self::GROWTH_TYPE_GROWTH => 'رشد',
        ];
    }

    public static function unitOptions(): array
    {
        return [
            self::UNIT_KG => 'کیلوگرم (kg)',
            self::UNIT_M => 'متر (m)',
            self::UNIT_HEAD => 'راس (head)',
        ];
    }

    public static function workflowOptions(): array
    {
        return [
            self::WORKFLOW_PENDING => 'در انتظار تأیید',
            self::WORKFLOW_APPROVED => 'تأیید شده',
            self::WORKFLOW_REJECTED => 'رد شده',
            self::WORKFLOW_NEEDS_EDIT => 'نیاز به ویرایش',
        ];
    }

    /** نوع گزارش سلامت */
    public const HEALTH_TYPE_TREATMENT = 'treatment';
    public const HEALTH_TYPE_DEHORNING = 'dehorning';
    public const HEALTH_TYPE_REMOVE_PRODUCT = 'remove_product';
    public const HEALTH_TYPE_VACCINATION = 'vaccination';
    public const HEALTH_TYPE_OTHER = 'other';

    public static function healthReportTypes(): array
    {
        return [
            self::HEALTH_TYPE_TREATMENT => 'درمان',
            self::HEALTH_TYPE_DEHORNING => 'شاخ‌سوزی',
            self::HEALTH_TYPE_REMOVE_PRODUCT => 'حذف محصول',
            self::HEALTH_TYPE_VACCINATION => 'واکسیناسیون',
            self::HEALTH_TYPE_OTHER => 'سایر',
        ];
    }

    public static function consumableUnitOptions(): array
    {
        return [
            'weight' => 'وزن',
            'count' => 'تعداد',
            'volume' => 'حجم',
        ];
    }

    protected static function boot(): void
    {
        parent::boot();
        static::addGlobalScope('order', function (Builder $builder) {
            $builder->orderByDesc('created_at');
        });
    }

    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function updatedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function project(): BelongsTo
    {
        return $this->belongsTo(Project::class, 'project_id');
    }

    public function producer(): BelongsTo
    {
        return $this->belongsTo(Producer::class, 'producer_id');
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }

    public function items(): HasMany
    {
        return $this->hasMany(ReportItem::class);
    }

    public function consumables(): HasMany
    {
        return $this->hasMany(ReportConsumable::class)->orderBy('sort_order');
    }

    public function invoiceItems(): HasMany
    {
        return $this->hasMany(ReportInvoiceItem::class)->orderBy('sort_order');
    }

    public function isHealthReport(): bool
    {
        return (int) $this->type === self::TYPE_HEALTH;
    }

    public function isGrowthReport(): bool
    {
        return (int) $this->type === self::TYPE_GROWTH;
    }

    public function itemsAverage(): ?float
    {
        $averages = $this->items
            ->map(fn (ReportItem $item) => $item->resolveAverage())
            ->filter(fn ($value) => $value !== null)
            ->values();

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

        return round((float) $averages->avg(), 3);
    }

    public function itemsMin(): ?float
    {
        $values = $this->items->pluck('min_value')->filter(fn ($v) => $v !== null);
        $singles = $this->items->pluck('value')->filter(fn ($v) => $v !== null);
        $all = $values->merge($singles);

        return $all->isEmpty() ? null : (float) $all->min();
    }

    public function itemsMax(): ?float
    {
        $values = $this->items->pluck('max_value')->filter(fn ($v) => $v !== null);
        $singles = $this->items->pluck('value')->filter(fn ($v) => $v !== null);
        $all = $values->merge($singles);

        return $all->isEmpty() ? null : (float) $all->max();
    }

    /** جیره: نوع مخلوط */
    public const MIX_MANUAL = 'manual';
    public const MIX_MACHINE = 'machine';
    public const MIX_COMBINED = 'combined';

    public static function mixTypeOptions(): array
    {
        return [
            self::MIX_MANUAL => 'دستی',
            self::MIX_MACHINE => 'ماشینی',
            self::MIX_COMBINED => 'ترکیبی',
        ];
    }

    public function rationIngredients(): HasMany
    {
        return $this->hasMany(ReportRationIngredient::class, 'report_id')->orderBy('sort_order');
    }

    public function feedingMeals(): HasMany
    {
        return $this->hasMany(ReportFeedingMeal::class, 'report_id')->orderBy('sort_order');
    }

    public function rationWeekly(): HasMany
    {
        return $this->hasMany(ReportRationWeekly::class, 'report_id')->orderBy('day_of_week');
    }

    public function feedingLogs(): HasMany
    {
        return $this->hasMany(ReportFeedingLog::class, 'report_id')->latest('fed_at_date');
    }

    public function isRationReport(): bool
    {
        return (int) $this->type === self::TYPE_RATION;
    }

    public function rationTotalQuantity(): float
    {
        return (float) $this->rationIngredients->sum('quantity_per_unit');
    }

    public function rationTotalCost(): float
    {
        return (float) $this->rationIngredients->sum(
            fn (ReportRationIngredient $item) => (float) $item->quantity_per_unit * (float) $item->price_per_unit
        );
    }

    public function rationHeadCount(): int
    {
        $fromItems = $this->relationLoaded('items')
            ? $this->items->count()
            : $this->items()->count();

        $fromProject = (int) ($this->project?->quantity ?? 0);

        return max(1, $fromItems ?: $fromProject ?: 1);
    }

    public function rationCostPerHead(): float
    {
        return $this->rationTotalCost() / $this->rationHeadCount();
    }

    public function rationSummary(): array
    {
        $ingredients = $this->rationIngredients;
        $totalQty = $this->rationTotalQuantity();

        return [
            'total_quantity' => round($totalQty, 3),
            'total_cost' => (int) round($this->rationTotalCost()),
            'cost_per_head' => (int) round($this->rationCostPerHead()),
            'head_count' => $this->rationHeadCount(),
            'ingredients_count' => $ingredients->count(),
            'meals_count' => $this->relationLoaded('feedingMeals')
                ? $this->feedingMeals->count()
                : $this->feedingMeals()->count(),
            'consumer_groups' => $this->relationLoaded('items')
                ? $this->items
                    ->groupBy(fn ($item) => $item->group_name ?: 'default')
                    ->map(fn ($group, $name) => [
                        'group_name' => $name === 'default' ? null : $name,
                        'products_count' => $group->count(),
                        'product_ids' => $group->pluck('product_id')->filter()->values(),
                    ])->values()
                : [],
        ];
    }
}

