<?php

namespace App\Core;

use PDO;

final class UnifiedAuth
{
    private PDO $db;
    private Auth $auth;

    public function __construct(PDO $db, Auth $auth)
    {
        $this->db = $db;
        $this->auth = $auth;
    }

    public function attempt(string $username, string $password, int $tenantId, bool $rememberMe = false): array
    {
        Session::start();
        $this->clearUnifiedState();

        $labOk = $this->auth->attempt($username, $password, $tenantId, $rememberMe);
        $doctorContext = $this->findDoctorContext($username, $password);
        $doctorOk = $doctorContext !== null;

        if (!$labOk && !$doctorOk) {
            return ['ok' => false, 'portals' => []];
        }

        $portals = [];
        if ($labOk) {
            $portals[] = 'lab';
        }
        if ($doctorOk) {
            $portals[] = 'doctor';
            $_SESSION['unified_doctor_context'] = $doctorContext;
        }

        $_SESSION['unified_logged_in'] = 1;
        $_SESSION['unified_principal_name'] = (string)($_SESSION['user_name'] ?? ($doctorContext['full_name'] ?? ''));
        $_SESSION['unified_available_portals'] = $portals;

        if (count($portals) === 1) {
            $_SESSION['unified_active_portal'] = $portals[0];
            $this->activatePortal($portals[0]);
        } else {
            $_SESSION['unified_active_portal'] = null;
        }

        return ['ok' => true, 'portals' => $portals];
    }

    public function availablePortals(): array
    {
        Session::start();
        $portals = $_SESSION['unified_available_portals'] ?? [];
        return is_array($portals) ? array_values(array_filter($portals, 'is_string')) : [];
    }

    public function isLoggedIn(): bool
    {
        Session::start();
        return !empty($_SESSION['unified_logged_in']);
    }

    public function activatePortal(string $portal): bool
    {
        Session::start();
        $portals = $this->availablePortals();
        if (!in_array($portal, $portals, true)) {
            return false;
        }

        if ($portal === 'doctor') {
            $ctx = $_SESSION['unified_doctor_context'] ?? null;
            if (!is_array($ctx)) {
                return false;
            }
            $this->writeDoctorSession($ctx);
        }
        if ($portal === 'patient') {
            $pid = (int)($_SESSION['portal_patient_id'] ?? 0);
            if ($pid <= 0) {
                return false;
            }
        }

        $_SESSION['unified_active_portal'] = $portal;
        $_SESSION['unified_last_portal'] = $portal;
        return true;
    }

    public function setPatientContext(int $patientId, int $tenantId, string $patientName = ''): void
    {
        Session::start();
        if ($patientId <= 0) {
            return;
        }
        $_SESSION['portal_patient_id'] = $patientId;
        $_SESSION['unified_patient_id'] = $patientId;
        $_SESSION['unified_patient_name'] = $patientName;
        if ($tenantId > 0) {
            $_SESSION['tenant_id'] = $tenantId;
        }

        $portals = $this->availablePortals();
        if (!in_array('patient', $portals, true)) {
            $portals[] = 'patient';
        }
        $_SESSION['unified_available_portals'] = array_values(array_unique($portals));
        $_SESSION['unified_logged_in'] = 1;
    }

    public function clearPortal(string $portal): void
    {
        Session::start();
        $portals = array_values(array_filter($this->availablePortals(), function ($p) use ($portal) {
            return $p !== $portal;
        }));
        $_SESSION['unified_available_portals'] = $portals;
        if (($_SESSION['unified_active_portal'] ?? null) === $portal) {
            $_SESSION['unified_active_portal'] = null;
        }
        if (($_SESSION['unified_last_portal'] ?? null) === $portal) {
            unset($_SESSION['unified_last_portal']);
        }

        if ($portal === 'patient') {
            unset($_SESSION['portal_patient_id'], $_SESSION['unified_patient_id'], $_SESSION['unified_patient_name']);
        } elseif ($portal === 'doctor') {
            unset(
                $_SESSION['unified_doctor_context'],
                $_SESSION['doctor_account_id'],
                $_SESSION['doctor_id'],
                $_SESSION['doctor_tenant_id'],
                $_SESSION['doctor_name'],
                $_SESSION['doctor_specialty'],
                $_SESSION['doctor_clinic'],
                $_SESSION['doctor_tenant_name'],
                $_SESSION['doctor_tenant_slug'],
                $_SESSION['doctor_last_activity']
            );
        }

        if (empty($portals)) {
            unset(
                $_SESSION['unified_logged_in'],
                $_SESSION['unified_principal_name'],
                $_SESSION['unified_available_portals'],
                $_SESSION['unified_active_portal'],
                $_SESSION['unified_last_portal']
            );
        }
    }

    public function redirectTargetAfterLogin(): string
    {
        $portals = $this->availablePortals();
        if (count($portals) > 1) {
            $last = (string)($_SESSION['unified_last_portal'] ?? '');
            if ($last !== '' && in_array($last, $portals, true)) {
                return $this->portalHome($last);
            }
            return 'index.php?page=choose_portal';
        }
        if (!empty($portals)) {
            return $this->portalHome($portals[0]);
        }
        return 'index.php?page=dashboard';
    }

    public function portalHome(string $portal): string
    {
        if ($portal === 'doctor') {
            return 'doctor.php?page=dashboard';
        }
        if ($portal === 'patient') {
            return 'index.php?page=patient_portal';
        }
        return 'index.php?page=dashboard';
    }

    public function syncFromDoctorSession(): bool
    {
        Session::start();
        $doctorAccountId = (int)($_SESSION['doctor_account_id'] ?? 0);
        $doctorId = (int)($_SESSION['doctor_id'] ?? 0);
        $doctorTenantId = (int)($_SESSION['doctor_tenant_id'] ?? 0);
        if ($doctorAccountId <= 0 || $doctorId <= 0 || $doctorTenantId <= 0) {
            return false;
        }

        $_SESSION['unified_logged_in'] = 1;
        if (empty($_SESSION['unified_principal_name'])) {
            $_SESSION['unified_principal_name'] = (string)($_SESSION['doctor_name'] ?? '');
        }

        $portals = $this->availablePortals();
        if (!in_array('doctor', $portals, true)) {
            $portals[] = 'doctor';
        }
        $_SESSION['unified_available_portals'] = array_values(array_unique($portals));
        $_SESSION['unified_active_portal'] = 'doctor';
        $_SESSION['unified_last_portal'] = 'doctor';
        return true;
    }

    private function findDoctorContext(string $username, string $password): ?array
    {
        try {
            $stmt = $this->db->prepare(
                'SELECT da.id, da.doctor_id, da.tenant_id, da.password_hash, d.full_name, d.specialty, d.clinic_name, t.name AS tenant_name, t.slug AS tenant_slug
                 FROM doctor_accounts da
                 JOIN doctors d ON d.id = da.doctor_id AND d.tenant_id = da.tenant_id
                 JOIN tenants t ON t.id = da.tenant_id
                 WHERE da.username = ? AND da.is_active = 1 AND t.status IN ("active","trial")
                 LIMIT 1'
            );
            $stmt->execute([$username]);
            $account = $stmt->fetch();
            if (!$account || !password_verify($password, (string)$account['password_hash'])) {
                return null;
            }
            return $account;
        } catch (\Throwable $e) {
            return null;
        }
    }

    private function writeDoctorSession(array $account): void
    {
        $_SESSION['doctor_account_id'] = (int)$account['id'];
        $_SESSION['doctor_id'] = (int)$account['doctor_id'];
        $_SESSION['doctor_tenant_id'] = (int)$account['tenant_id'];
        $_SESSION['doctor_name'] = (string)($account['full_name'] ?? '');
        $_SESSION['doctor_specialty'] = (string)($account['specialty'] ?? '');
        $_SESSION['doctor_clinic'] = (string)($account['clinic_name'] ?? '');
        $_SESSION['doctor_tenant_name'] = (string)($account['tenant_name'] ?? '');
        $_SESSION['doctor_tenant_slug'] = (string)($account['tenant_slug'] ?? '');
        $_SESSION['doctor_last_activity'] = time();
        try {
            $this->db->prepare('UPDATE doctor_accounts SET last_login_at = NOW() WHERE id = ?')->execute([(int)$account['id']]);
        } catch (\Throwable $e) {}
    }

    private function clearUnifiedState(): void
    {
        unset(
            $_SESSION['unified_logged_in'],
            $_SESSION['unified_principal_name'],
            $_SESSION['unified_available_portals'],
            $_SESSION['unified_active_portal'],
            $_SESSION['unified_last_portal'],
            $_SESSION['unified_doctor_context'],
            $_SESSION['doctor_account_id'],
            $_SESSION['doctor_id'],
            $_SESSION['doctor_tenant_id'],
            $_SESSION['doctor_name'],
            $_SESSION['doctor_specialty'],
            $_SESSION['doctor_clinic'],
            $_SESSION['doctor_tenant_name'],
            $_SESSION['doctor_tenant_slug'],
            $_SESSION['doctor_last_activity']
        );
    }
}
