<?php

namespace App\Domain\Shared\Models;

use App\Domain\Email\Models\EmailTheme;
use App\Domain\Shared\Actions\InitializeTeamKeyEscrowAction;
use App\Domain\Shared\Enums\TeamRole;
use App\Infrastructure\Encryption\CredentialEncryption;
use App\Models\User;
use Database\Factories\Domain\Shared\TeamFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
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\HasMany;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

/**
 * @property string $id
 * @property string $name
 * @property string $slug
 * @property string|null $owner_id
 * @property bool $is_platform
 * @property bool $claude_code_vps_allowed
 * @property bool $assistant_ui_artifacts_allowed
 * @property array<string, mixed>|null $settings
 * @property string|null $plan
 * @property array<string, mixed>|null $custom_limits
 * @property string|null $sub_program_slug
 * @property float|null $credit_margin_multiplier
 * @property int|null $max_credits_per_call
 * @property int|null $byok_platform_fee_per_call
 * @property string|null $credential_key
 * @property string|null $default_email_theme_id
 * @property array<string, mixed>|null $allowed_models
 * @property string|null $widget_public_key
 * @property array<string, mixed>|null $dashboard_config
 * @property string|null $git_webhook_secret
 * @property string|null $default_bug_fix_workflow_id
 * @property float|null $signal_relevance_threshold
 * @property Carbon|null $created_at
 * @property Carbon|null $updated_at
 */
class Team extends Model
{
    use HasFactory, HasUuids;

    protected static function booted(): void
    {
        static::creating(function (self $team) {
            if (! $team->credential_key) {
                $team->credential_key = CredentialEncryption::generateKey();
            }
            if (! $team->widget_public_key) {
                $team->widget_public_key = 'wk_'.Str::random(40);
            }
        });

        static::created(function (self $team) {
            app(InitializeTeamKeyEscrowAction::class)->execute($team);
        });

        static::deleting(function (self $team) {
            if ($team->is_platform) {
                throw new \RuntimeException('The platform team cannot be deleted.');
            }
        });
    }

    protected $fillable = [
        'name',
        'slug',
        'owner_id',
        'is_platform',
        'claude_code_vps_allowed',
        'assistant_ui_artifacts_allowed',
        'settings',
        'credential_key',
        'default_email_theme_id',
        'allowed_models',
        'widget_public_key',
        'dashboard_config',
        'git_webhook_secret',
        'default_bug_fix_workflow_id',
        'signal_relevance_threshold',
    ];

    protected $hidden = [
        'credential_key',
        'git_webhook_secret',
    ];

    protected function casts(): array
    {
        return [
            'is_platform' => 'boolean',
            'claude_code_vps_allowed' => 'boolean',
            'assistant_ui_artifacts_allowed' => 'boolean',
            'settings' => 'array',
            'allowed_models' => 'array',
            'dashboard_config' => 'array',
            'credential_key' => 'encrypted',
            'signal_relevance_threshold' => 'float',
        ];
    }

    protected static function newFactory()
    {
        return TeamFactory::new();
    }

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

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'team_user')
            ->withPivot('role')
            ->withTimestamps();
    }

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

    public function activeCredentialFor(string $provider): ?TeamProviderCredential
    {
        return $this->providerCredentials()
            ->where('provider', $provider)
            ->where('is_active', true)
            ->first();
    }

    public function defaultEmailTheme(): BelongsTo
    {
        return $this->belongsTo(EmailTheme::class, 'default_email_theme_id');
    }

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

    public function memberRole(User $user): ?TeamRole
    {
        $pivot = $this->users()->where('user_id', $user->id)->first()?->pivot;

        return $pivot ? TeamRole::from($pivot->role) : null;
    }

    /**
     * Community edition: all features are available.
     */
    public function hasFeature(string $feature): bool
    {
        return true;
    }

    /**
     * Community edition has no per-team override — falls through to config.
     */
    public function effectiveMarginMultiplier(): float
    {
        return (float) config('llm_pricing.margin_multiplier', 1.30);
    }

    /**
     * Community edition has no per-team cap — falls through to config.
     */
    public function effectiveMaxCreditsPerCall(): ?int
    {
        $configMax = config('llm_pricing.max_credits_per_call');

        return $configMax !== null ? (int) $configMax : null;
    }

    /**
     * Community edition has no per-team BYOK fee — falls through to config.
     */
    public function effectiveByokPlatformFee(): int
    {
        return (int) config('llm_pricing.byok_platform_fee_per_call', 0);
    }

    /**
     * Look up the owner_id for a team without instantiating the model and
     * without relying on TeamScope. Used as a userId fallback in actions
     * that don't have an originating user context (e.g. team-default
     * routing) — required by VPS gateway's userId check.
     */
    public static function ownerIdFor(?string $teamId): ?string
    {
        if (! $teamId) {
            return null;
        }

        return self::withoutGlobalScopes()
            ->where('id', $teamId)
            ->value('owner_id');
    }
}
