<?php

namespace App\Models\Tenants;

use App\Models\Commons\File;
use App\Models\Members\User;
use App\Models\Members\UserRole;
use App\Models\Members\UserTenant;
use App\Models\Permissions\Role;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * @mixin IdeHelperTenant
 */
class Tenant extends Model
{
    use ModelTrait, SoftDeletes;

    protected $fillable = [
        'company_name',
        'code',
        'email',
        'phone',
        'address',
        'business_num',
        'corp_reg_no',
        'ceo_name',
        'homepage',
        'fax',
        'logo',
        'admin_memo',
        'options',
        'tenant_st_code',
        'billing_tp_code',
    ];

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

    protected $casts = [
        'trial_ends_at' => 'datetime',
        'expires_at' => 'datetime',
        'last_paid_at' => 'datetime',
        'max_users' => 'integer',
        'options' => 'array',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    protected $hidden = [
        'deleted_at',
    ];

    /**
     * 활성화된 테넌트만 조회하는 스코프
     */
    public function scopeActive($query)
    {
        return $query->whereIn('tenant_st_code', ['trial', 'active']);
    }

    /**
     * 테넌트가 활성 상태인지 확인
     */
    public function isActive(): bool
    {
        return in_array($this->tenant_st_code, ['trial', 'active']);
    }

    /**
     * 테넌트가 트라이얼 상태인지 확인
     */
    public function isTrial(): bool
    {
        return $this->tenant_st_code === 'trial';
    }

    // 관계 정의 (예시)
    public function plan()
    {
        return $this->belongsTo(Plan::class, 'plan_id');
    }

    public function subscription()
    {
        return $this->belongsTo(Subscription::class, 'subscription_id');
    }

    public function userTenants()
    {
        return $this->hasMany(UserTenant::class);
    }

    public function users()
    {
        return $this->belongsToMany(User::class, 'user_tenants');
    }

    public function roles()
    {
        return $this->hasMany(Role::class);
    }

    public function userRoles()
    {
        return $this->hasMany(UserRole::class);
    }

    public function files()
    {
        return $this->morphMany(File::class, 'fileable');
    }

    /**
     * Get storage usage percentage
     */
    public function getStorageUsagePercentage(): float
    {
        if (! $this->storage_limit || $this->storage_limit == 0) {
            return 0;
        }

        return ($this->storage_used / $this->storage_limit) * 100;
    }

    /**
     * Check if storage is near limit (90%)
     */
    public function isStorageNearLimit(): bool
    {
        return $this->getStorageUsagePercentage() >= 90;
    }

    /**
     * Check if storage quota exceeded
     */
    public function isStorageExceeded(): bool
    {
        return $this->storage_used > $this->storage_limit;
    }

    /**
     * Check if in grace period
     */
    public function isInGracePeriod(): bool
    {
        return $this->storage_grace_period_until && now()->lessThan($this->storage_grace_period_until);
    }

    /**
     * Check if upload is allowed
     */
    public function canUpload(int $fileSize = 0): array
    {
        $newUsage = $this->storage_used + $fileSize;

        // Check if exceeds limit
        if ($newUsage > $this->storage_limit) {
            // Check grace period
            if ($this->isInGracePeriod()) {
                return [
                    'allowed' => true,
                    'warning' => true,
                    'message' => __('file.storage_exceeded_grace_period', [
                        'until' => $this->storage_grace_period_until->format('Y-m-d'),
                    ]),
                ];
            }

            // Grace period expired - block upload
            return [
                'allowed' => false,
                'message' => __('file.storage_quota_exceeded'),
            ];
        }

        // Check if near limit (90%)
        $percentage = ($newUsage / $this->storage_limit) * 100;
        if ($percentage >= 90 && ! $this->storage_warning_sent_at) {
            // Send warning (once)
            $this->update([
                'storage_warning_sent_at' => now(),
                'storage_grace_period_until' => now()->addDays(7),
            ]);

            // TODO: Dispatch email notification
            // dispatch(new SendStorageWarningEmail($this));
        }

        return ['allowed' => true];
    }

    /**
     * Increment storage usage
     */
    public function incrementStorage(int $bytes): void
    {
        $this->increment('storage_used', $bytes);
    }

    /**
     * Decrement storage usage
     */
    public function decrementStorage(int $bytes): void
    {
        $this->decrement('storage_used', max(0, $bytes));
    }

    /**
     * Get human-readable storage used
     */
    public function getStorageUsedFormatted(): string
    {
        return $this->formatBytes($this->storage_used);
    }

    /**
     * Get human-readable storage limit
     */
    public function getStorageLimitFormatted(): string
    {
        return $this->formatBytes($this->storage_limit);
    }

    /**
     * Format bytes to human-readable string
     */
    private function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= (1 << (10 * $pow));

        return round($bytes, 2).' '.$units[$pow];
    }
}
