<?php
declare(strict_types=1);

namespace App\Modules\ParentAuth\Services;

use App\Core\App;

final class ParentAuthService
{
    private \App\Core\Database $db;

    public function __construct()
    {
        $this->db = App::getInstance()->db();
    }

    public function findByPhone(string $phone): ?array
    {
        return $this->db->selectOne(
            "SELECT * FROM parent_accounts WHERE phone = ? AND is_active = 1",
            [$phone]
        );
    }

    public function verifyPin(array $parent, string $pin): bool
    {
        if (empty($parent['pin_hash'])) {
            return false;
        }
        return password_verify($pin, $parent['pin_hash']);
    }

    public function generateOtp(int $parentId): string
    {
        $otp = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
        $expiresAt = date('Y-m-d H:i:s', time() + 300);

        $this->db->update('parent_accounts', [
            'otp_code' => $otp,
            'otp_expires_at' => $expiresAt,
        ], 'id = ?', [$parentId]);

        return $otp;
    }

    public function verifyOtp(array $parent, string $otp): bool
    {
        if (empty($parent['otp_code']) || empty($parent['otp_expires_at'])) {
            return false;
        }

        if ($parent['otp_code'] !== $otp) {
            return false;
        }

        if ($parent['otp_expires_at'] < date('Y-m-d H:i:s')) {
            return false;
        }

        $this->db->update('parent_accounts', [
            'otp_code' => null,
            'otp_expires_at' => null,
        ], 'id = ?', [(int) $parent['id']]);

        return true;
    }

    public function createToken(int $parentId, string $name = 'mobile', ?string $deviceInfo = null): array
    {
        $config = App::getInstance()->config('api.token', []);
        $maxTokens = $config['max_per_parent'] ?? 5;
        $ttlHours = $config['parent_ttl_hours'] ?? 2160;

        $activeCount = $this->db->selectOne(
            "SELECT COUNT(*) as cnt FROM parent_tokens WHERE parent_id = ? AND is_revoked = 0",
            [$parentId]
        );

        if ((int) ($activeCount['cnt'] ?? 0) >= $maxTokens) {
            $oldest = $this->db->selectOne(
                "SELECT id FROM parent_tokens WHERE parent_id = ? AND is_revoked = 0 ORDER BY last_used_at ASC LIMIT 1",
                [$parentId]
            );
            if ($oldest) {
                $this->db->update('parent_tokens', ['is_revoked' => 1], 'id = ?', [(int) $oldest['id']]);
            }
        }

        $token = bin2hex(random_bytes(32));
        $expiresAt = date('Y-m-d H:i:s', time() + ($ttlHours * 3600));

        $this->db->insert('parent_tokens', [
            'parent_id' => $parentId,
            'token' => $token,
            'name' => $name,
            'device_info' => $deviceInfo,
            'expires_at' => $expiresAt,
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        $this->db->update('parent_accounts', [
            'last_login_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$parentId]);

        return [
            'token' => $token,
            'expires_at' => $expiresAt,
        ];
    }

    public function refreshToken(string $currentToken, int $parentId): array
    {
        $this->db->update('parent_tokens', [
            'is_revoked' => 1,
        ], '`token` = ? AND parent_id = ?', [$currentToken, $parentId]);

        return $this->createToken($parentId);
    }

    public function revokeToken(string $token): void
    {
        $this->db->update('parent_tokens', [
            'is_revoked' => 1,
        ], '`token` = ?', [$token]);
    }
}
