<?php

declare(strict_types=1);

namespace App\Services\TenantReviews;

use App\Models\Tenant;
use App\Models\TenantReview;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\RoleCapabilityMap;
use App\Support\Auth\Capabilities;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;

final class TenantReviewRegisterService
{
    /**
     * @return array<int, Tenant>
     */
    public function authorizedTenants(User $user, Workspace $workspace): array
    {
        $roles = RoleCapabilityMap::rolesWithCapability(Capabilities::TENANT_REVIEW_VIEW);

        return $user->tenants()
            ->where('tenants.workspace_id', (int) $workspace->getKey())
            ->wherePivotIn('role', $roles)
            ->orderBy('tenants.name')
            ->get()
            ->keyBy(static fn (Tenant $tenant): int => (int) $tenant->getKey())
            ->all();
    }

    public function query(User $user, Workspace $workspace): Builder
    {
        $tenantIds = array_keys($this->authorizedTenants($user, $workspace));

        return TenantReview::query()
            ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
            ->forWorkspace((int) $workspace->getKey())
            ->whereIn('tenant_id', $tenantIds === [] ? [-1] : $tenantIds)
            ->latest('generated_at')
            ->latest('id');
    }

    public function latestPublishedQuery(User $user, Workspace $workspace): Builder
    {
        $tenantIds = array_keys($this->authorizedTenants($user, $workspace));

        $rankedReviews = TenantReview::query()
            ->select([
                'tenant_reviews.id',
                'tenant_reviews.tenant_id',
                'tenant_reviews.published_at',
                'tenant_reviews.generated_at',
            ])
            ->selectRaw('ROW_NUMBER() OVER (PARTITION BY tenant_id ORDER BY published_at DESC, generated_at DESC, id DESC) as rn')
            ->forWorkspace((int) $workspace->getKey())
            ->whereIn('tenant_id', $tenantIds === [] ? [-1] : $tenantIds)
            ->published();

        $latestPublishedIds = DB::query()
            ->fromSub($rankedReviews, 'ranked_tenant_reviews')
            ->where('rn', 1)
            ->select('id');

        return TenantReview::query()
            ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
            ->forWorkspace((int) $workspace->getKey())
            ->whereIn('tenant_reviews.id', $latestPublishedIds)
            ->orderByDesc('published_at')
            ->orderByDesc('generated_at')
            ->orderByDesc('id');
    }

    public function customerWorkspaceTenantQuery(User $user, Workspace $workspace): Builder
    {
        $tenantIds = array_keys($this->authorizedTenants($user, $workspace));

        return Tenant::query()
            ->where('workspace_id', (int) $workspace->getKey())
            ->whereIn('id', $tenantIds === [] ? [-1] : $tenantIds)
            ->whereHas('tenantReviews', fn ($query) => $query->published())
            ->with([
                'tenantReviews' => fn ($query) => $query
                    ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
                    ->published()
                    ->orderByDesc('published_at')
                    ->orderByDesc('generated_at')
                    ->orderByDesc('id')
                    ->limit(1),
            ])
            ->orderBy('name');
    }

    public function canAccessWorkspace(User $user, Workspace $workspace): bool
    {
        return WorkspaceMembership::query()
            ->where('workspace_id', (int) $workspace->getKey())
            ->where('user_id', (int) $user->getKey())
            ->exists();
    }
}
