<?php

namespace App\Models;

use App\Enums\LicenseStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\Auth;
use Monzer\FilamentWorkflows\Traits\TrackWorkflowModelEvents;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class WellLicense extends Model implements HasMedia
{
    use HasFactory, InteractsWithMedia, LogsActivity, TrackWorkflowModelEvents;

    protected $fillable = [
        'association_id',
        'state_id',
        'city_id',
        'center_id',
        'well_name',
        'lat',
        'lng',
        'well_depth',
        'well_diameter',
        'pump_size',
        'withdrawal_amount',
        'status',
        'ministry_license_number',
        'ministry_license_start_date',
        'ministry_license_end_date',
        'delegation_start_date',
        'delegation_end_date',
        'created_by',
        'location',
    ];

    protected $appends = [
        'location',
    ];

    protected $casts = [
        'status' => LicenseStatus::class,
        'lat' => 'decimal:8',
        'lng' => 'decimal:8',
        'well_depth' => 'decimal:2',
        'well_diameter' => 'decimal:2',
        'pump_size' => 'decimal:2',
        'withdrawal_amount' => 'decimal:2',
        'ministry_license_start_date' => 'date',
        'ministry_license_end_date' => 'date',
        'delegation_start_date' => 'date',
        'delegation_end_date' => 'date',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    protected $attributes = [
        'status' => LicenseStatus::PENDING_REQUIREMENTS,
    ];

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

        static::creating(function ($model) {
            if (Auth::check()) {
                $model->created_by = Auth::id();
            }
        });

        static::created(function ($model) {
            // Auto-create default license requirements
            $defaultRequirements = [
                'رفع مساحي يوضح الموقع العام وموقع البئر',
                'إفصاح البئر',
                'تحليل عينة مياه البئر',
                'صك الملكية او قرار تخصيص او إفادة من امارة المركز بإن الموقع لا يوجد عليها نزاعات قبلية أو فردية',
                'صور للبئر',
            ];

            foreach ($defaultRequirements as $requirementName) {
                $model->requirements()->create([
                    'name' => $requirementName,
                    'status' => LicenseRequirement::STATUS_PENDING,
                ]);
            }
        });
    }

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

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

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

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

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

    public function residentialGatherings(): BelongsToMany
    {
        return $this->belongsToMany(ResidentialGathering::class);
    }

    public function stationLicenses(): BelongsToMany
    {
        return $this->belongsToMany(StationLicense::class, 'station_license_well_license');
    }

    public function requirements(): MorphMany
    {
        return $this->morphMany(LicenseRequirement::class, 'licenseable');
    }

    /**
     * Register media collections
     */
    public function registerMediaCollections(): void
    {
        // Ministry license file (required when approving from FINAL_APPROVAL)
        $this->addMediaCollection('ministry_license')
            ->acceptsMimeTypes([
                'application/pdf',
            ]);
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->useLogName('well_license')
            ->logOnly([
                'well_name',
                'state_id',
                'city_id',
                'center_id',
                'lat',
                'lng',
                'well_depth',
                'well_diameter',
                'pump_size',
                'withdrawal_amount',
                'status',
                'ministry_license_number',
                'ministry_license_start_date',
                'ministry_license_end_date',
                'delegation_start_date',
                'delegation_end_date',
            ])
            ->logOnlyDirty();
    }

    /**
     * Get the next status for approval workflow
     */
    public function getNextStatus(): ?LicenseStatus
    {
        return match ($this->status) {
            LicenseStatus::CREATED => LicenseStatus::PENDING_REQUIREMENTS,
            LicenseStatus::PENDING_REQUIREMENTS => LicenseStatus::INITIAL_APPROVAL,
            LicenseStatus::INITIAL_APPROVAL => LicenseStatus::FINAL_APPROVAL,
            LicenseStatus::FINAL_APPROVAL => LicenseStatus::APPROVED,
            LicenseStatus::APPROVED => null,
            LicenseStatus::REJECTED => null,
        };
    }

    /**
     * Get the previous status for sending back workflow
     */
    public function getPreviousStatus(): ?LicenseStatus
    {
        return match ($this->status) {
            LicenseStatus::CREATED => null,
            LicenseStatus::PENDING_REQUIREMENTS => LicenseStatus::CREATED,
            LicenseStatus::INITIAL_APPROVAL => LicenseStatus::PENDING_REQUIREMENTS,
            LicenseStatus::FINAL_APPROVAL => LicenseStatus::INITIAL_APPROVAL,
            LicenseStatus::APPROVED => LicenseStatus::FINAL_APPROVAL,
            LicenseStatus::REJECTED => null,
        };
    }

    /**
     * Check if license can be sent back to previous stage
     */
    public function canSendBackToPreviousStage(): bool
    {
        // if the status is either APPROVED or REJECTED, we cannot send back
        if (
            $this->status === LicenseStatus::APPROVED
            || $this->status === LicenseStatus::REJECTED
            || $this->status === LicenseStatus::PENDING_REQUIREMENTS
        ) {
            return false;
        }

        return $this->getPreviousStatus() !== null;
    }

    /**
     * Send license back to previous stage
     */
    public function sendBackToPreviousStage(string $notes = ''): bool
    {
        $previousStatus = $this->getPreviousStatus();
        if (! $previousStatus) {
            return false;
        }

        $oldStatus = $this->status;
        $this->status = $previousStatus;
        $this->save();

        // Log the send back activity
        activity()
            ->performedOn($this)
            ->causedBy(Auth::user())
            ->event('send_back')
            ->withProperties([
                'old_status' => $oldStatus->value,
                'new_status' => $previousStatus->value,
                'notes' => $notes,
                'action' => 'sent_back',
            ])
            ->log("Well license sent back from {$oldStatus->value} to {$previousStatus->value}");

        return true;
    }

    /**
     * Check if license can be approved to next stage
     */
    public function canApproveToNextStage(): bool
    {
        return $this->getNextStatus() !== null;
    }

    /**
     * Approve license to next stage
     */
    public function approveToNextStage(string $notes = ''): bool
    {
        $nextStatus = $this->getNextStatus();
        if (! $nextStatus) {
            return false;
        }

        $oldStatus = $this->status;
        $this->status = $nextStatus;
        $this->save();

        // Log the approval activity
        activity()
            ->performedOn($this)
            ->causedBy(Auth::user())
            ->event('approved')
            ->withProperties([
                'old_status' => $oldStatus->value,
                'new_status' => $nextStatus->value,
                'action' => 'approved',
                'notes' => $notes,
            ])
            ->log('Well license approved to next stage');

        return true;
    }

    /**
     * Reject license
     */
    public function reject(string $notes = ''): void
    {
        $oldStatus = $this->status;
        $this->status = LicenseStatus::REJECTED;
        $this->save();

        // Log the rejection activity
        activity()
            ->performedOn($this)
            ->causedBy(Auth::user())
            ->event('rejected')
            ->withProperties([
                'old_status' => $oldStatus->value,
                'new_status' => LicenseStatus::REJECTED->value,
                'action' => 'rejected',
                'notes' => $notes,
            ])
            ->log('Well license rejected');
    }

    /**
     * Check if license can be rejected
     */
    public function canReject(): bool
    {
        // if the status is either APPROVED or REJECTED, we cannot reject
        if (
            $this->status === LicenseStatus::APPROVED
            || $this->status === LicenseStatus::REJECTED
        ) {
            return false;
        }

        return true;
    }

    /**
     * Get current status notes from activity log
     */
    public function getCurrentStatusNotesAttribute(): ?string
    {
        $activity = $this->activities()
            ->whereIn('event', ['send_back', 'approved', 'rejected'])
            ->where('properties->new_status', $this->status->value)
            ->orderBy('created_at', 'desc')
            ->first();

        return $activity?->properties['notes'] ?? null;
    }

    /**
     * Returns the 'lat' and 'lng' attributes as the computed 'location' attribute,
     * as a standard Google Maps style Point array with 'lat' and 'lng' attributes.
     *
     * Used by the Filament Google Maps package.
     *
     * Requires the 'location' attribute be included in this model's $fillable array.
     */
    public function getLocationAttribute(): array
    {
        return [
            'lat' => (float) $this->lat,
            'lng' => (float) $this->lng,
        ];
    }

    /**
     * Takes a Google style Point array of 'lat' and 'lng' values and assigns them to the
     * 'lat' and 'lng' attributes on this model.
     *
     * Used by the Filament Google Maps package.
     *
     * Requires the 'location' attribute be included in this model's $fillable array.
     */
    public function setLocationAttribute(?array $location): void
    {
        if (is_array($location)) {
            $this->attributes['lat'] = $location['lat'];
            $this->attributes['lng'] = $location['lng'];
            unset($this->attributes['location']);
        }
    }

    /**
     * Get the lat and lng attribute/field names used on this table
     *
     * Used by the Filament Google Maps package.
     *
     * @return string[]
     */
    public static function getLatLngAttributes(): array
    {
        return [
            'lat' => 'lat',
            'lng' => 'lng',
        ];
    }

    /**
     * Get the name of the computed location attribute
     *
     * Used by the Filament Google Maps package.
     */
    public static function getComputedLocation(): string
    {
        return 'location';
    }

    /**
     * Get activity for a specific status
     */
    public function getActivityForStatus($status)
    {
        return $this->activities()
            ->where('properties->old_status', $status)
            ->where('event', 'approved')
            ->latest()
            ->first();
    }

    /**
     * Check if a status has been completed (approved)
     */
    public function isStatusCompleted($status): bool
    {
        $activity = $this->getActivityForStatus($status);

        return $activity !== null;
    }
}
