<?php

namespace MintyPHP\Service\User;

use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Repository\Support\RepoQuery;
use MintyPHP\Repository\User\UserReadRepositoryInterface;
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
use MintyPHP\Service\Audit\UserLifecycleAuditInterface;

class UserLifecycleRestoreService
{
    public function __construct(
        private readonly UserReadRepositoryInterface $userReadRepository,
        private readonly UserWriteRepositoryInterface $userWriteRepository,
        private readonly UserLifecycleAuditInterface $userLifecycleAuditService,
        private readonly DatabaseSessionRepository $databaseSessionRepository,
        private readonly UserSettingsGateway $userSettingsGateway
    ) {
    }

    public function restoreFromLifecycleAudit(int $auditId, int $actorUserId): array
    {
        if ($auditId <= 0 || $actorUserId <= 0) {
            return ['ok' => false, 'error' => 'invalid_request'];
        }

        $transactionStarted = false;
        try {
            $this->databaseSessionRepository->beginTransaction();
            $transactionStarted = true;

            $event = $this->userLifecycleAuditService->findDeleteEventForRestore($auditId, true);
            if (!$event) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'audit_event_not_found'];
            }
            if (!empty($event['restored_at'])) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'audit_event_already_restored'];
            }

            $snapshot = $this->userLifecycleAuditService->decryptSnapshot($event);
            if (!$snapshot) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'snapshot_unavailable'];
            }

            $uuid = trim((string) ($snapshot['uuid'] ?? ''));
            $email = trim((string) ($snapshot['email'] ?? ''));
            if ($uuid === '' || $email === '') {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'snapshot_invalid'];
            }

            if ($this->userReadRepository->findByUuid($uuid)) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'restore_uuid_exists'];
            }
            if ($this->userReadRepository->findByEmail($email)) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'restore_email_exists'];
            }

            $createdId = $this->userWriteRepository->create([
                'uuid' => $uuid,
                'first_name' => trim((string) ($snapshot['first_name'] ?? '')),
                'last_name' => trim((string) ($snapshot['last_name'] ?? '')),
                'email' => $email,
                'profile_description' => $this->nullableText($snapshot['profile_description'] ?? null),
                'job_title' => $this->nullableText($snapshot['job_title'] ?? null),
                'phone' => $this->nullableText($snapshot['phone'] ?? null),
                'mobile' => $this->nullableText($snapshot['mobile'] ?? null),
                'short_dial' => $this->nullableText($snapshot['short_dial'] ?? null),
                'address' => $this->nullableText($snapshot['address'] ?? null),
                'postal_code' => $this->nullableText($snapshot['postal_code'] ?? null),
                'city' => $this->nullableText($snapshot['city'] ?? null),
                'country' => $this->nullableText($snapshot['country'] ?? null),
                'region' => $this->nullableText($snapshot['region'] ?? null),
                'hire_date' => $this->nullableDate($snapshot['hire_date'] ?? null),
                'password' => $this->randomPassword(),
                'locale' => $this->nullableText($snapshot['locale'] ?? null),
                'totp_secret' => '',
                'theme' => $this->normalizeTheme($snapshot['theme'] ?? null),
                'primary_tenant_id' => null,
                'current_tenant_id' => null,
                'created_by' => $actorUserId,
                'active' => 0,
                'active_changed_at' => gmdate('Y-m-d H:i:s'),
                'active_changed_by' => $actorUserId,
            ]);
            if (!$createdId) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'restore_create_failed'];
            }
            $restoredUserId = (int) $createdId;

            $marked = $this->userLifecycleAuditService->markDeleteEventRestored(
                $auditId,
                $actorUserId,
                $restoredUserId
            );
            if (!$marked) {
                $this->rollbackQuietly();
                return ['ok' => false, 'error' => 'restore_mark_failed'];
            }

            $this->userLifecycleAuditService->logRestore(
                RepoQuery::uuidV4(),
                'manual',
                [
                    'deactivate_days' => (int) ($event['policy_deactivate_days'] ?? 0),
                    'delete_days' => (int) ($event['policy_delete_days'] ?? 0),
                ],
                $actorUserId,
                [
                    'id' => $restoredUserId,
                    'uuid' => $uuid,
                    'email' => $email,
                ],
                'success',
                null
            );

            $this->databaseSessionRepository->commitTransaction();
            $transactionStarted = false;
            return [
                'ok' => true,
                'restored_user_id' => $restoredUserId,
                'restored_user_uuid' => $uuid,
                'audit_id' => $auditId,
            ];
        } catch (\Throwable $exception) {
            if ($transactionStarted) {
                $this->rollbackQuietly();
            }
            return ['ok' => false, 'error' => 'restore_unexpected_error'];
        }
    }

    private function rollbackQuietly(): void
    {
        try {
            $this->databaseSessionRepository->rollbackTransaction();
        } catch (\Throwable $exception) {
            // no-op
        }
    }

    private function nullableText(mixed $value): ?string
    {
        $value = trim((string) $value);
        return $value !== '' ? $value : null;
    }

    private function nullableDate(mixed $value): ?string
    {
        $value = trim((string) $value);
        if ($value === '') {
            return null;
        }
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
            return null;
        }
        return $value;
    }

    private function randomPassword(): string
    {
        return bin2hex(random_bytes(24));
    }

    private function normalizeTheme(mixed $value): string
    {
        $theme = is_scalar($value) ? (string) $value : null;
        return $this->userSettingsGateway->normalizeTheme($theme);
    }
}
