<?php

declare(strict_types=1);

namespace App\Policies;

use App\Contracts\OwnedByUser;
use App\Enums\UserRole;
use App\Models\Domain;
use App\Models\User;
use Illuminate\Auth\Access\Response;

/**
 * Who may act on a domain in someone's portfolio.
 *
 * A domain is private inventory, not a public record: until it is listed,
 * nobody outside the owner and support has any business knowing it exists. The
 * base policy's 404-shaped denial is therefore the right default here.
 *
 * @extends OwnershipPolicy
 */
final class DomainPolicy extends OwnershipPolicy
{
    /**
     * Adding a domain requires an account that can transact, which the base
     * policy already enforces. Being a seller is not required at this point:
     * the seller profile is created lazily when someone first acts as a seller,
     * and adding inventory is exactly that moment.
     */
    public function create(User $user): Response
    {
        return parent::create($user);
    }

    /**
     * Ownership proof may be attempted by the owner alone.
     *
     * Explicitly not available to staff. Support proving ownership on a
     * seller's behalf would make the marketplace's central guarantee something
     * an employee can assert rather than something the DNS demonstrates.
     */
    public function verify(User $user, Domain $domain): Response
    {
        if (! $this->owns($user, $domain)) {
            return $this->notFound();
        }

        if (! $user->canTransact()) {
            return Response::deny('Confirm your email address before verifying a domain.');
        }

        return $domain->verification_status->canRetry()
            ? Response::allow()
            : Response::deny('A verification check is already in progress.');
    }

    /**
     * Removing a domain is refused while it has an open listing.
     *
     * Otherwise deleting the inventory row would orphan a live offer, and a
     * buyer could be negotiating over a name the seller has already discarded.
     * The listing has to be withdrawn first, which is a visible act.
     *
     * Requires the `listings` relation to be loaded, or it will be counted.
     */
    public function delete(User $user, OwnedByUser $resource): Response
    {
        if (! $this->owns($user, $resource)) {
            return $this->notFound();
        }

        /** @var Domain $resource */
        $hasOpenListing = $resource->listings()
            ->whereNull('deleted_at')
            ->whereNotNull('open_domain_id')
            ->exists();

        return $hasOpenListing
            ? Response::deny('Withdraw the listing on this domain before removing it.')
            : Response::allow();
    }

    /**
     * The private verification token and DNS instructions.
     *
     * Owner only, and deliberately not readable by support: the token is the
     * thing that proves control, so handing it to anyone else would make the
     * proof transferable.
     */
    public function viewVerificationToken(User $user, Domain $domain): Response
    {
        return $this->owns($user, $domain) ? Response::allow() : $this->notFound();
    }

    /**
     * Registrar and expiry detail, which support needs for transfer disputes.
     */
    public function viewRegistrarDetail(User $user, Domain $domain): Response
    {
        if ($this->owns($user, $domain)) {
            return Response::allow();
        }

        return $user->hasAtLeastRole(UserRole::Support) ? Response::allow() : $this->notFound();
    }
}
