<?php

declare(strict_types=1);

namespace App\Services\Auth;

use App\Models\Tenant;
use App\Models\TenantMembership;
use App\Models\User;
use App\Services\Intune\AuditLogger;
use App\Support\Audit\AuditActionId;
use Illuminate\Support\Facades\DB;

class TenantDiagnosticsService
{
    public function __construct(public AuditLogger $auditLogger) {}

    public function tenantHasNoOwners(Tenant $tenant): bool
    {
        return ! TenantMembership::query()
            ->where('tenant_id', (int) $tenant->getKey())
            ->where('role', 'owner')
            ->exists();
    }

    public function userHasDuplicateMemberships(Tenant $tenant, User $user): bool
    {
        return TenantMembership::query()
            ->where('tenant_id', (int) $tenant->getKey())
            ->where('user_id', (int) $user->getKey())
            ->count() > 1;
    }

    public function mergeDuplicateMembershipsForUser(Tenant $tenant, User $actor, User $member): void
    {
        DB::transaction(function () use ($tenant, $actor, $member): void {
            $memberships = TenantMembership::query()
                ->where('tenant_id', (int) $tenant->getKey())
                ->where('user_id', (int) $member->getKey())
                ->orderBy('created_at')
                ->get();

            if ($memberships->count() <= 1) {
                return;
            }

            $roles = $memberships->pluck('role')->all();
            $roleToKeep = $this->highestRole($roles);

            $membershipToKeep = $memberships->firstWhere('role', $roleToKeep) ?? $memberships->first();
            if (! $membershipToKeep instanceof TenantMembership) {
                return;
            }

            $idsToDelete = $memberships
                ->reject(fn (TenantMembership $m): bool => $m->getKey() === $membershipToKeep->getKey())
                ->pluck($membershipToKeep->getKeyName())
                ->all();

            $membershipToKeep->forceFill([
                'role' => $roleToKeep,
            ])->save();

            TenantMembership::query()
                ->whereIn($membershipToKeep->getKeyName(), $idsToDelete)
                ->delete();

            $this->auditLogger->log(
                tenant: $tenant,
                action: AuditActionId::TenantMembershipDuplicatesMerged->value,
                context: [
                    'metadata' => [
                        'member_user_id' => (int) $member->getKey(),
                        'kept_membership_id' => (string) $membershipToKeep->getKey(),
                        'deleted_membership_ids' => array_values(array_map('strval', $idsToDelete)),
                        'result_role' => $roleToKeep,
                        'source_roles' => $roles,
                    ],
                ],
                actorId: (int) $actor->getKey(),
                actorEmail: $actor->email,
                actorName: $actor->name,
                status: 'success',
                resourceType: 'tenant',
                resourceId: (string) $tenant->getKey(),
            );
        });
    }

    /**
     * @param  array<int, string|null>  $roles
     */
    private function highestRole(array $roles): string
    {
        $priority = [
            'owner' => 3,
            'manager' => 2,
            'readonly' => 1,
        ];

        $bestRole = 'readonly';
        $bestScore = 0;

        foreach ($roles as $role) {
            $score = $priority[$role] ?? 0;
            if ($score > $bestScore) {
                $bestScore = $score;
                $bestRole = (string) $role;
            }
        }

        return $bestRole;
    }
}
