"""Persistent, single-use Admin login challenges shared by Passenger workers."""
import hashlib
import hmac
import secrets
import sqlite3
import time
from pathlib import Path


class AdminEmailOTP:
    def __init__(self, path, key):
        self.path = Path(path)
        self.key = key

    def _connect(self):
        self.path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
        db = sqlite3.connect(self.path, timeout=10, isolation_level=None)
        self.path.chmod(0o600)
        db.execute('CREATE TABLE IF NOT EXISTS otp (id TEXT PRIMARY KEY, email TEXT, binding TEXT, digest TEXT, payload TEXT, created REAL, expires REAL, attempts INTEGER)')
        return db

    def _digest(self, token, code):
        return hmac.new(self.key, (token + ':' + code).encode(), hashlib.sha256).hexdigest()

    def issue(self, email, binding, payload):
        now = time.time()
        with self._connect() as db:
            db.execute('BEGIN IMMEDIATE')
            db.execute('DELETE FROM otp WHERE created < ?', (now - 600,))
            sent_recently = db.execute('SELECT COUNT(*) FROM otp WHERE email=? AND created>?', (email, now - 600)).fetchone()[0]
            if sent_recently >= 3:
                raise ValueError('Maximum 3 codes sent. Please try again after 10 minutes.')
            db.execute('UPDATE otp SET payload=?, expires=0 WHERE email=?', ('', email))
            token, code = secrets.token_urlsafe(32), f'{secrets.randbelow(1000000):06d}'
            db.execute('INSERT INTO otp VALUES (?,?,?,?,?,?,?,0)', (token, email, binding, self._digest(token, code), payload, now, now + 300))
            db.commit()
        return token, code

    def cancel(self, token):
        with self._connect() as db:
            db.execute('UPDATE otp SET payload=?, expires=0 WHERE id=?', ('', token))

    def verify(self, token, code, binding):
        with self._connect() as db:
            db.execute('BEGIN IMMEDIATE')
            row = db.execute('SELECT binding,digest,payload,expires,attempts FROM otp WHERE id=?', (token,)).fetchone()
            if not row or row[3] <= time.time() or row[4] >= 5 or not hmac.compare_digest(row[0], binding):
                return None
            valid = len(code) == 6 and code.isascii() and code.isdigit() and hmac.compare_digest(row[1], self._digest(token, code))
            if valid:
                db.execute('UPDATE otp SET payload=?, expires=0 WHERE id=?', ('', token))
            else:
                db.execute('UPDATE otp SET attempts=attempts+1 WHERE id=?', (token,))
                db.execute('UPDATE otp SET payload=?, expires=0 WHERE id=? AND attempts>=5', ('', token))
            db.commit()
            return row[2] if valid else None
