<?php

namespace App\Models;

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

class ProductionBatch extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'branch_id',
        'product_id',
        'recipe_id',
        'produced_by',
        'batch_number',
        'batch_size',
        'batch_size_value',
        'total_scoops',
        'remaining_scoops',
        'sold_scoops',
        'wasted_scoops',
        'cost_per_scoop',
        'total_weight_grams',
        'remaining_weight_grams',
        'sold_weight_grams',
        'wasted_weight_grams',
        'status',
        'produced_at',
        'notes',
    ];

    protected $casts = [
        'batch_size_value' => 'decimal:2',
        'total_scoops' => 'integer',
        'remaining_scoops' => 'integer',
        'sold_scoops' => 'integer',
        'wasted_scoops' => 'integer',
        'cost_per_scoop' => 'decimal:4',
        'total_weight_grams' => 'decimal:2',
        'remaining_weight_grams' => 'decimal:2',
        'sold_weight_grams' => 'decimal:2',
        'wasted_weight_grams' => 'decimal:2',
        'produced_at' => 'datetime',
    ];

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($batch) {
            if (empty($batch->batch_number)) {
                $batch->batch_number = static::generateBatchNumber($batch->branch_id);
            }
        });
    }

    public static function generateBatchNumber(int $branchId): string
    {
        $date = now()->format('Ymd');
        $prefix = "BATCH-{$branchId}-{$date}";

        $count = static::where('batch_number', 'like', "{$prefix}%")->count() + 1;

        return "{$prefix}-" . str_pad($count, 4, '0', STR_PAD_LEFT);
    }

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

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

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

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

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

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

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

    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    public function scopeForBranch($query, int $branchId)
    {
        return $query->where('branch_id', $branchId);
    }

    public function scopeForProduct($query, int $productId)
    {
        return $query->where('product_id', $productId);
    }

    public function scopeHasRemainingScoops($query)
    {
        return $query->where('remaining_scoops', '>', 0);
    }

    public function isActive(): bool
    {
        return $this->status === 'active';
    }

    public function hasRemainingScoops(): bool
    {
        return $this->remaining_scoops > 0;
    }

    public function deductScoops(int $count): bool
    {
        if ($this->remaining_scoops < $count) {
            return false;
        }

        $this->remaining_scoops -= $count;
        $this->sold_scoops += $count;

        if ($this->remaining_scoops === 0) {
            $this->status = 'finished';
        }

        return $this->save();
    }

    public function recordWaste(int $count, ?string $reason = null): bool
    {
        if ($this->remaining_scoops < $count) {
            $count = $this->remaining_scoops;
        }

        $this->remaining_scoops -= $count;
        $this->wasted_scoops += $count;

        if ($this->remaining_scoops === 0) {
            $this->status = 'finished';
        }

        if ($reason) {
            $this->notes = ($this->notes ? $this->notes . "\n" : '') . "Waste: {$count} scoops - {$reason}";
        }

        return $this->save();
    }

    public function markAsExpired(): bool
    {
        $this->status = 'expired';
        $this->wasted_scoops += $this->remaining_scoops;
        $this->remaining_scoops = 0;

        return $this->save();
    }

    public function calculateTotalCost(): float
    {
        return $this->ingredients->sum('total_cost');
    }

    public function getUsagePercentageAttribute(): float
    {
        if ($this->total_scoops === 0) {
            return 0;
        }

        return round(($this->sold_scoops / $this->total_scoops) * 100, 2);
    }

    /**
     * Deduct weight from batch (new weight-based system)
     */
    public function deductWeight(float $weightGrams): bool
    {
        if ($this->remaining_weight_grams === null || $this->remaining_weight_grams < $weightGrams) {
            return false;
        }

        $this->remaining_weight_grams -= $weightGrams;
        $this->sold_weight_grams += $weightGrams;

        if ($this->remaining_weight_grams <= 0) {
            $this->status = 'finished';
        }

        return $this->save();
    }

    /**
     * Record weight waste (new weight-based system)
     */
    public function recordWeightWaste(float $weightGrams, ?string $reason = null): bool
    {
        if ($this->remaining_weight_grams === null) {
            return false;
        }

        if ($this->remaining_weight_grams < $weightGrams) {
            $weightGrams = $this->remaining_weight_grams;
        }

        $this->remaining_weight_grams -= $weightGrams;
        $this->wasted_weight_grams += $weightGrams;

        if ($this->remaining_weight_grams <= 0) {
            $this->status = 'finished';
        }

        if ($reason) {
            $this->notes = ($this->notes ? $this->notes . "\n" : '') . "Waste: {$weightGrams}g - {$reason}";
        }

        return $this->save();
    }

    /**
     * Check if batch has remaining weight
     */
    public function hasRemainingWeight(): bool
    {
        return $this->remaining_weight_grams !== null && $this->remaining_weight_grams > 0;
    }

    /**
     * Get weight usage percentage
     */
    public function getWeightUsagePercentageAttribute(): float
    {
        if ($this->total_weight_grams === null || $this->total_weight_grams == 0) {
            return 0;
        }

        return round(($this->sold_weight_grams / $this->total_weight_grams) * 100, 2);
    }
}
