<?php

namespace App\Models\Tenants;

use App\Traits\Auditable;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * 구독 모델
 *
 * @property int $id
 * @property int $tenant_id 테넌트 ID
 * @property int $plan_id 요금제 ID
 * @property Carbon $started_at 시작일
 * @property Carbon|null $ended_at 종료일
 * @property string $status 상태
 * @property Carbon|null $cancelled_at 취소일
 * @property string|null $cancel_reason 취소 사유
 *
 * @mixin IdeHelperSubscription
 */
class Subscription extends Model
{
    use Auditable, SoftDeletes;

    // =========================================================================
    // 상수 정의
    // =========================================================================

    /** 구독 상태 */
    public const STATUS_ACTIVE = 'active';

    public const STATUS_CANCELLED = 'cancelled';

    public const STATUS_EXPIRED = 'expired';

    public const STATUS_PENDING = 'pending';

    public const STATUS_SUSPENDED = 'suspended';

    public const STATUSES = [
        self::STATUS_ACTIVE,
        self::STATUS_CANCELLED,
        self::STATUS_EXPIRED,
        self::STATUS_PENDING,
        self::STATUS_SUSPENDED,
    ];

    /** 상태 라벨 */
    public const STATUS_LABELS = [
        self::STATUS_ACTIVE => '활성',
        self::STATUS_CANCELLED => '취소됨',
        self::STATUS_EXPIRED => '만료됨',
        self::STATUS_PENDING => '대기',
        self::STATUS_SUSPENDED => '일시정지',
    ];

    // =========================================================================
    // 모델 설정
    // =========================================================================

    protected $fillable = [
        'tenant_id',
        'plan_id',
        'started_at',
        'ended_at',
        'status',
        'cancelled_at',
        'cancel_reason',
        'created_by',
        'updated_by',
        'deleted_by',
    ];

    protected $casts = [
        'started_at' => 'datetime',
        'ended_at' => 'datetime',
        'cancelled_at' => 'datetime',
    ];

    protected $attributes = [
        'status' => self::STATUS_PENDING,
    ];

    // =========================================================================
    // 스코프
    // =========================================================================

    /**
     * 활성 구독만
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_ACTIVE);
    }

    /**
     * 유효한 구독 (활성 + 미만료)
     */
    public function scopeValid(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_ACTIVE)
            ->where(function ($q) {
                $q->whereNull('ended_at')
                    ->orWhere('ended_at', '>', now());
            });
    }

    /**
     * 만료 예정 (N일 이내)
     */
    public function scopeExpiringWithin(Builder $query, int $days): Builder
    {
        return $query->where('status', self::STATUS_ACTIVE)
            ->whereNotNull('ended_at')
            ->where('ended_at', '<=', now()->addDays($days))
            ->where('ended_at', '>', now());
    }

    /**
     * 특정 테넌트
     */
    public function scopeForTenant(Builder $query, int $tenantId): Builder
    {
        return $query->where('tenant_id', $tenantId);
    }

    // =========================================================================
    // 관계
    // =========================================================================

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

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

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

    // =========================================================================
    // 접근자
    // =========================================================================

    /**
     * 상태 라벨
     */
    public function getStatusLabelAttribute(): string
    {
        return self::STATUS_LABELS[$this->status] ?? $this->status;
    }

    /**
     * 만료 여부
     */
    public function getIsExpiredAttribute(): bool
    {
        if (! $this->ended_at) {
            return false;
        }

        return $this->ended_at->isPast();
    }

    /**
     * 남은 일수
     */
    public function getRemainingDaysAttribute(): ?int
    {
        if (! $this->ended_at) {
            return null; // 무제한
        }

        if ($this->is_expired) {
            return 0;
        }

        return now()->diffInDays($this->ended_at, false);
    }

    /**
     * 유효 여부
     */
    public function getIsValidAttribute(): bool
    {
        return $this->status === self::STATUS_ACTIVE && ! $this->is_expired;
    }

    /**
     * 총 결제 금액
     */
    public function getTotalPaidAttribute(): float
    {
        return (float) $this->payments()
            ->where('status', Payment::STATUS_COMPLETED)
            ->sum('amount');
    }

    // =========================================================================
    // 헬퍼 메서드
    // =========================================================================

    /**
     * 구독 활성화
     */
    public function activate(): bool
    {
        if ($this->status !== self::STATUS_PENDING) {
            return false;
        }

        $this->status = self::STATUS_ACTIVE;
        $this->started_at = $this->started_at ?? now();

        // 종료일 계산 (요금제 주기에 따라)
        if (! $this->ended_at && $this->plan) {
            $this->ended_at = match ($this->plan->billing_cycle) {
                Plan::BILLING_MONTHLY => $this->started_at->copy()->addMonth(),
                Plan::BILLING_YEARLY => $this->started_at->copy()->addYear(),
                Plan::BILLING_LIFETIME => null,
                default => $this->started_at->copy()->addMonth(),
            };
        }

        return $this->save();
    }

    /**
     * 구독 갱신
     */
    public function renew(?Carbon $newEndDate = null): bool
    {
        if ($this->status !== self::STATUS_ACTIVE) {
            return false;
        }

        if ($newEndDate) {
            $this->ended_at = $newEndDate;
        } elseif ($this->plan) {
            $baseDate = $this->ended_at ?? now();
            $this->ended_at = match ($this->plan->billing_cycle) {
                Plan::BILLING_MONTHLY => $baseDate->copy()->addMonth(),
                Plan::BILLING_YEARLY => $baseDate->copy()->addYear(),
                Plan::BILLING_LIFETIME => null,
                default => $baseDate->copy()->addMonth(),
            };
        }

        return $this->save();
    }

    /**
     * 구독 취소
     */
    public function cancel(?string $reason = null): bool
    {
        if (! in_array($this->status, [self::STATUS_ACTIVE, self::STATUS_PENDING])) {
            return false;
        }

        $this->status = self::STATUS_CANCELLED;
        $this->cancelled_at = now();
        $this->cancel_reason = $reason;

        return $this->save();
    }

    /**
     * 구독 일시정지
     */
    public function suspend(): bool
    {
        if ($this->status !== self::STATUS_ACTIVE) {
            return false;
        }

        $this->status = self::STATUS_SUSPENDED;

        return $this->save();
    }

    /**
     * 구독 재개
     */
    public function resume(): bool
    {
        if ($this->status !== self::STATUS_SUSPENDED) {
            return false;
        }

        $this->status = self::STATUS_ACTIVE;

        return $this->save();
    }

    /**
     * 취소 가능 여부
     */
    public function isCancellable(): bool
    {
        return in_array($this->status, [self::STATUS_ACTIVE, self::STATUS_PENDING]);
    }
}
