<?php

namespace App\Livewire\Portal;

use App\Domain\Compliance\Enums\ConsentType;
use App\Domain\Compliance\Models\AccountDeletionRequest;
use App\Domain\Compliance\Services\AccountDeletionService;
use App\Domain\Compliance\Services\ConsentService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Livewire\Portal\Concerns\PortalScreen;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

/**
 * Consent, data export, and deleting the account.
 *
 * Apple 5.1.1(v) and Google both refuse an app that creates accounts without
 * letting them be deleted from inside the app, so this screen is what makes a
 * store submission possible at all — not a refinement to add afterwards.
 *
 * It is also the only place in this product where a member can see what they
 * agreed to and change their mind. Before this there was no consent record
 * anywhere in the schema, while the product published children's photographs
 * on a public website.
 */
#[Layout('layouts.portal')]
#[Title('الخصوصية والبيانات')]
class PortalPrivacy extends Component
{
    use PortalScreen;

    /** @var array<string, bool> */
    public array $consents = [];

    public bool $confirmingDeletion = false;

    public string $deletionReason = '';

    public string $deletionPassword = '';

    public function mount(ConsentService $service): void
    {
        $this->authorizePortal();

        $current = $service->currentFor(auth()->user(), $this->portal()->activeParticipant());

        foreach (ConsentType::cases() as $type) {
            $this->consents[$type->value] = $current[$type->value] ?? false;
        }
    }

    public function saveConsents(ConsentService $service): void
    {
        try {
            $service->recordMany(
                $this->consents,
                auth()->user(),
                $this->portal()->activeParticipant(),
                request()->ip(),
                request()->userAgent(),
            );
        } catch (DomainException $e) {
            $this->addError('consents', $e->getMessage());

            return;
        }

        session()->flash('success', __('تم حفظ تفضيلاتك'));
    }

    /**
     * The export is generated on demand and streamed, never stored. A file of
     * somebody's entire record sitting on disk waiting to be collected is a
     * second copy of exactly the data they asked to control.
     */
    public function export(AccountDeletionService $service)
    {
        $payload = $service->export(auth()->user());

        $name = 'my-data-' . now()->format('Y-m-d') . '.json';

        return response()->streamDownload(
            fn () => print(json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)),
            $name,
            ['Content-Type' => 'application/json; charset=utf-8'],
        );
    }

    public function requestDeletion(AccountDeletionService $service): void
    {
        try {
            $service->request(
                auth()->user(),
                $this->deletionReason ?: null,
                $this->deletionPassword,
                request()->ip(),
            );
        } catch (DomainException $e) {
            $this->addError('deletionPassword', $e->getMessage());

            return;
        }

        $this->reset(['deletionPassword', 'deletionReason', 'confirmingDeletion']);

        session()->flash('success', __('تم استلام طلب حذف الحساب'));
    }

    public function cancelDeletion(AccountDeletionService $service): void
    {
        $request = AccountDeletionRequest::where('user_id', auth()->id())
            ->whereIn('status', ['pending', 'blocked'])
            ->first();

        if ($request) {
            $service->cancel($request);
            session()->flash('success', __('تم إلغاء طلب الحذف'));
        }
    }

    public function render()
    {
        $deletion = AccountDeletionRequest::where('user_id', auth()->id())
            ->whereIn('status', ['pending', 'blocked'])
            ->first();

        return view('livewire.portal.portal-privacy', [
            'types' => ConsentType::cases(),
            'deletion' => $deletion,
            // Shown up front rather than after the member commits: "you cannot
            // delete this yet, and here is exactly why" is respectful; a
            // refusal at the last step is not.
            'blockers' => app(AccountDeletionService::class)->blockers(auth()->user()),
        ]);
    }
}
