<?php

namespace Database\Factories;

use App\Models\Finding;
use App\Models\ManagedEnvironment;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Finding>
 */
class FindingFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $seenAt = now();

        return [
            'managed_environment_id' => ManagedEnvironment::factory(),
            'finding_type' => Finding::FINDING_TYPE_DRIFT,
            'scope_key' => hash('sha256', fake()->uuid()),
            'baseline_operation_run_id' => null,
            'current_operation_run_id' => null,
            'fingerprint' => hash('sha256', fake()->uuid()),
            'subject_type' => 'assignment',
            'subject_external_id' => fake()->uuid(),
            'severity' => Finding::SEVERITY_MEDIUM,
            'status' => Finding::STATUS_NEW,
            'acknowledged_at' => null,
            'acknowledged_by_user_id' => null,
            'first_seen_at' => $seenAt,
            'last_seen_at' => $seenAt,
            'times_seen' => 1,
            'sla_days' => 14,
            'due_at' => $seenAt->copy()->addDays(14),
            'owner_user_id' => null,
            'assignee_user_id' => null,
            'triaged_at' => null,
            'in_progress_at' => null,
            'reopened_at' => null,
            'closed_at' => null,
            'closed_by_user_id' => null,
            'closed_reason' => null,
            'recurrence_key' => null,
            'evidence_jsonb' => [],
        ];
    }

    /**
     * State for permission posture findings.
     */
    public function permissionPosture(): static
    {
        return $this->state(fn (array $attributes): array => [
            'finding_type' => Finding::FINDING_TYPE_PERMISSION_POSTURE,
            'source' => 'permission_check',
            'subject_type' => 'permission',
            'subject_external_id' => 'DeviceManagementConfiguration.ReadWrite.All',
            'severity' => Finding::SEVERITY_MEDIUM,
            'evidence_jsonb' => [
                'permission_key' => 'DeviceManagementConfiguration.ReadWrite.All',
                'permission_type' => 'application',
                'expected_status' => 'granted',
                'actual_status' => 'missing',
                'blocked_features' => ['policy-sync', 'backup'],
                'checked_at' => now()->toIso8601String(),
            ],
        ]);
    }

    /**
     * State for triaged findings.
     */
    public function triaged(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_TRIAGED,
            'triaged_at' => now(),
        ]);
    }

    /**
     * State for in-progress findings.
     */
    public function inProgress(): static
    {
        return $this->state(function (array $attributes): array {
            $triagedAt = now()->subMinute();

            return [
                'status' => Finding::STATUS_IN_PROGRESS,
                'triaged_at' => $attributes['triaged_at'] ?? $triagedAt,
                'in_progress_at' => now(),
            ];
        });
    }

    /**
     * State for resolved findings.
     */
    public function resolved(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_RESOLVED,
            'resolved_at' => now(),
            'resolved_reason' => Finding::RESOLVE_REASON_REMEDIATED,
        ]);
    }

    public function verifiedCleared(string $reason = Finding::RESOLVE_REASON_NO_LONGER_DRIFTING): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_RESOLVED,
            'resolved_at' => now(),
            'resolved_reason' => $reason,
        ]);
    }

    /**
     * State for reopened findings.
     */
    public function reopened(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_REOPENED,
            'reopened_at' => now(),
            'resolved_at' => null,
            'resolved_reason' => null,
            'closed_at' => null,
            'closed_reason' => null,
            'closed_by_user_id' => null,
        ]);
    }

    public function ownedBy(?int $userId): static
    {
        return $this->state(fn (array $attributes): array => [
            'owner_user_id' => $userId,
        ]);
    }

    public function assignedTo(?int $userId): static
    {
        return $this->state(fn (array $attributes): array => [
            'assignee_user_id' => $userId,
        ]);
    }

    public function dueWithinHours(int $hours): static
    {
        return $this->state(fn (array $attributes): array => [
            'due_at' => now()->addHours($hours),
        ]);
    }

    public function overdueByHours(int $hours = 1): static
    {
        return $this->state(fn (array $attributes): array => [
            'due_at' => now()->subHours($hours),
        ]);
    }

    /**
     * State for closed findings.
     */
    public function closed(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_CLOSED,
            'closed_at' => now(),
            'closed_reason' => Finding::CLOSE_REASON_DUPLICATE,
        ]);
    }

    /**
     * State for risk accepted findings.
     */
    public function riskAccepted(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => Finding::STATUS_RISK_ACCEPTED,
            'closed_at' => now(),
            'closed_reason' => Finding::CLOSE_REASON_ACCEPTED_RISK,
        ]);
    }

    /**
     * State for Entra admin roles findings.
     */
    public function entraAdminRoles(): static
    {
        return $this->state(fn (array $attributes): array => [
            'finding_type' => Finding::FINDING_TYPE_ENTRA_ADMIN_ROLES,
            'source' => 'entra.admin_roles',
            'severity' => Finding::SEVERITY_CRITICAL,
            'subject_type' => 'role_assignment',
            'evidence_jsonb' => [
                'role_display_name' => 'Global Administrator',
                'principal_display_name' => 'Admin User',
                'principal_type' => 'user',
                'principal_id' => fake()->uuid(),
                'role_definition_id' => fake()->uuid(),
                'role_template_id' => '62e90394-69f5-4237-9190-012177145e10',
                'directory_scope_id' => '/',
                'is_built_in' => true,
                'measured_at' => now()->toIso8601String(),
            ],
        ]);
    }
}
