<?php
namespace Mtc\Shop\Assessment;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * BMI Ethnicity Model
 *
 * Handles BMI cutoff thresholds based on ethnicity categories
 * Supports BMI range validation with custom messages for different ethnicity groups
 *
 * @property string $bmi_category
 * @property int $ethnicity_id
 * @property float|null $cutoff_low
 * @property float|null $cutoff_high
 * @property string|null $message
 * @property bool $is_active
 * @property AssessmentEthnicity $ethnicity
 */
class BmiEthnicity extends Model
{
    protected $table = 'assessment_bmi_ethnicities';

    protected $fillable = [
        'bmi_category',
        'ethnicity_id',
        'cutoff_low',
        'cutoff_high',
        'message',
        'is_active',
    ];

    protected $casts = [
        'cutoff_low' => 'float',
        'cutoff_high' => 'float',
        'is_active' => 'boolean',
    ];

    const BMI_CATEGORIES = [
        'Obesity',
        'Overweight',

    ];

    // 'Underweight',
    // 'Normal Weight',

    /**
     * Get the ethnicity that owns this BMI ethnicity record
     *
     * @return BelongsTo
     */
    public function ethnicity(): BelongsTo
    {
        return $this->belongsTo(AssessmentEthnicity::class, 'ethnicity_id');
    }

    /**
     * Get ethnicity name through relationship
     *
     * @return string|null
     */
    public function getEthnicityNameAttribute(): ?string
    {
        return $this->ethnicity?->name;
    }

    /**
     * Scope to get only active BMI ethnicity records
     *
     * @param Builder $query
     * @return Builder
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope to filter by ethnicity ID
     *
     * @param Builder $query
     * @param int $ethnicityId
     * @return Builder
     */
    public function scopeByEthnicityId(Builder $query, int $ethnicityId): Builder
    {
        return $query->where('ethnicity_id', $ethnicityId);
    }

    /**
     * Scope to filter by ethnicity name
     *
     * @param Builder $query
     * @param string $ethnicityName
     * @return Builder
     */
    public function scopeByEthnicityName(Builder $query, string $ethnicityName): Builder
    {
        return $query->whereHas('ethnicity', function ($q) use ($ethnicityName) {
            $q->where('name', $ethnicityName);
        });
    }

    /**
     * Scope to filter by BMI category
     *
     * @param Builder $query
     * @param string $category
     * @return Builder
     */
    public function scopeByCategory(Builder $query, string $category): Builder
    {
        return $query->where('bmi_category', $category);
    }

    /**
     * Check if BMI is within the acceptable range
     *
     * @param float $bmi_value
     * @return bool
     */
    public function isWithinRange(float $bmi_value): bool
    {
        // Check if BMI is above the low cutoff
        if ($this->cutoff_low !== null && $bmi_value < $this->cutoff_low) {
            return false;
        }

        // Check if BMI is below the high cutoff (if set)
        if ($this->cutoff_high !== null && $bmi_value > $this->cutoff_high) {
            return false;
        }

        return true;
    }

    /**
     * Check if BMI should be blocked (outside acceptable range)
     *
     * @param float $bmi_value
     * @return bool
     */
    public function shouldBlock(float $bmi_value): bool
    {
        return !$this->isWithinRange($bmi_value);
    }

    /**
     * Get the appropriate restriction level for a BMI value
     * 0 - no restriction (within range), 2 - block (outside range)
     *
     * @param float $bmi_value
     * @return int
     */
    public function getRestrictionLevel(float $bmi_value): int
    {
        if ($this->shouldBlock($bmi_value)) {
            return 2; // Block
        }

        return 0; // No restriction
    }

    /**
     * Get the appropriate message for a BMI value
     *
     * @param float $bmi_value
     * @return string|null
     */
    public function getRestrictionMessage(float $bmi_value): ?string
    {
        if ($this->shouldBlock($bmi_value)) {
            return $this->message;
        }

        return null;
    }

    /**
     * Check if patient is eligible for treatment based on BMI
     *
     * @param float $bmi_value
     * @return bool
     */
    public function isEligibleForTreatment(float $bmi_value): bool
    {
        return $this->isWithinRange($bmi_value);
    }

    /**
     * Get formatted BMI range description
     *
     * @return string
     */
    public function getBmiRangeDescription(): string
    {
        if ($this->cutoff_low !== null && $this->cutoff_high !== null) {
            return "BMI between {$this->cutoff_low} and {$this->cutoff_high}";
        } elseif ($this->cutoff_low !== null) {
            return "BMI {$this->cutoff_low} or higher";
        } elseif ($this->cutoff_high !== null) {
            return "BMI {$this->cutoff_high} or lower";
        }

        return "No BMI restrictions";
    }

    /**
     * Find matching BMI ethnicity record for given ethnicity and category
     *
     * @param string $ethnicityName
     * @param string|null $bmi_category
     * @return self|null
     */
    public static function findForEthnicity(string $ethnicityName, ?string $bmi_category = null): ?self
    {
        $query = self::active()->byEthnicityName($ethnicityName);

        if ($bmi_category) {
            $query->byCategory($bmi_category);
        }

        return $query->first();
    }

    /**
     * Find matching BMI ethnicity record for given ethnicity ID and category
     *
     * @param int $ethnicityId
     * @param string|null $bmi_category
     * @return self|null
     */
    public static function findForEthnicityId(int $ethnicityId, ?string $bmi_category = null): ?self
    {
        $query = self::active()->byEthnicityId($ethnicityId);

        if ($bmi_category) {
            $query->byCategory($bmi_category);
        }

        return $query->first();
    }

    /**
     * Get all active categories
     *
     * @return \Illuminate\Support\Collection
     */
    public static function getActiveCategories(): \Illuminate\Support\Collection
    {
        return self::active()
            ->select('bmi_category')
            ->distinct()
            ->pluck('bmi_category');
    }

    /**
     * Get all active ethnicities
     *
     * @return \Illuminate\Support\Collection
     */
    public static function getActiveEthnicities(): \Illuminate\Support\Collection
    {
        return self::active()
            ->with('ethnicity')
            ->get()
            ->pluck('ethnicity.name')
            ->unique()
            ->filter();
    }

    /**
     * Get ethnicity records with BMI categories
     *
     * @return \Illuminate\Support\Collection
     */
    public static function getEthnicityRecords(): \Illuminate\Support\Collection
    {
        $records = self::active()
            ->with('ethnicity')
            ->get()
            ->groupBy(function ($record) {
                return $record->ethnicity?->id;
            });

        return $records->map(function ($ethnicityRecords) {
            $ethnicity = $ethnicityRecords->first()->ethnicity;


            return [
                'ethnicity_id' => $ethnicity?->id,
                'ethnicity_name' => $ethnicity?->name,
                'ethnicity_description' => $ethnicity?->description,
                'categories' => $ethnicityRecords->filter(function ($record) {
                    return $record->cutoff_low !== null;
                })->map(function ($record) {
                    return [
                        'bmi_category' => $record->bmi_category,
                        'cutoff_low' => $record->cutoff_low,
                        'cutoff_high' => $record->cutoff_high,
                        'message' => $record->message,
                    ];
                })->values()->toArray(),
            ];
        })->values();
    }

    /**
     * Create default BMI ethnicity records
     *
     * @return void
     */
    public static function createDefaultBmiEthnicityRecords(): void
    {
        // First ensure we have default ethnicities
        AssessmentEthnicity::createDefaultEthnicities();

        $defaultEthnicities = AssessmentEthnicity::getActiveEthnicities();
        $bmiCategories = self::BMI_CATEGORIES;

        foreach ($defaultEthnicities as $ethnicity) {
            foreach ($bmiCategories as $bmiCategory) {
                // Check if record already exists
                if (
                    !self::where('ethnicity_id', $ethnicity->id)
                        ->where('bmi_category', $bmiCategory)
                        ->exists()
                ) {

                    self::create([
                        'ethnicity_id' => $ethnicity->id,
                        'bmi_category' => $bmiCategory,
                        'cutoff_low' => null,
                        'cutoff_high' => null,
                        'message' => 'Your calculated BMI score indicates that you are suitable to receive treatments from one of our programmes',
                        'is_active' => true,
                    ]);
                }
            }
        }
    }
}