'use client'

import { API_BASE, PortalApiError, portalRequest } from './portal-api'

export type AccessRole = 'admin' | 'doctor' | 'student' | null

export interface AccessPayload {
  authenticated?: boolean
  user?: string | null
  roles?: string[]
  adminRoles?: string[]
  canAccessAdmin?: boolean
  entityPermissions?: Record<string, { read: boolean; write: boolean }>
}

export interface AuthUser {
  id: string
  name: string
  email: string
  role: AccessRole
  roles: string[]
  adminRoles: string[]
  canAccessAdmin: boolean
}

function inferRole(payload: AccessPayload): AccessRole {
  const roles = Array.isArray(payload.roles) ? payload.roles : []

  if (roles.includes('Instructor')) {
    return 'doctor'
  }
  if (roles.includes('Student')) {
    return 'student'
  }
  if (payload.canAccessAdmin || (payload.adminRoles || []).length > 0) {
    return 'admin'
  }
  return null
}

function normalizeUserName(user: string) {
  const local = user.split('@')[0] || user
  return local.replace(/[._-]+/g, ' ').trim() || user
}

export function mapAccessToUser(payload: AccessPayload | null | undefined): AuthUser | null {
  if (!payload?.authenticated || !payload.user) {
    return null
  }

  const email = String(payload.user)
  const roles = Array.isArray(payload.roles) ? payload.roles : []
  const adminRoles = Array.isArray(payload.adminRoles) ? payload.adminRoles : []

  return {
    id: email,
    email,
    name: normalizeUserName(email),
    role: inferRole(payload),
    roles,
    adminRoles,
    canAccessAdmin: Boolean(payload.canAccessAdmin),
  }
}

export async function fetchCurrentAccess() {
  return portalRequest<AccessPayload>('/api/access/me')
}

export async function loginWithFrappe(username: string, password: string) {
  let resolvedUsername = username
  try {
    const resolver = await portalRequest<{ identifier?: string }>(
      `/api/access/resolve-login?identifier=${encodeURIComponent(username)}`,
      { method: 'GET' },
    )
    if (resolver?.identifier) {
      resolvedUsername = String(resolver.identifier)
    }
  } catch {
    resolvedUsername = username
  }

  const portalLogin = await fetch(`${API_BASE}/api/method/aau_university.api.v1.access.portal_login`, {
    method: 'POST',
    credentials: 'include',
    cache: 'no-store',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    mode: 'cors',
    body: JSON.stringify({
      identifier: resolvedUsername,
      password,
    }),
  })

  const portalLoginText = await portalLogin.text()
  let portalPayload: any = null
  if (portalLoginText) {
    try {
      portalPayload = JSON.parse(portalLoginText)
    } catch {
      portalPayload = { message: portalLoginText }
    }
  }

  if (portalLogin.ok && !portalPayload?.exc && portalPayload?.ok !== false) {
    return portalPayload
  }
  const message =
    portalPayload?.error?.message ||
    portalPayload?._server_messages ||
    portalPayload?.message ||
    portalPayload?.exception ||
    portalLogin.statusText ||
    'Login failed'

  throw new PortalApiError(String(message), `HTTP_${portalLogin.status}`, portalLogin.status)
}

export async function logoutFromFrappe() {
  await fetch(`${API_BASE}/api/method/logout`, {
    method: 'POST',
    credentials: 'include',
    cache: 'no-store',
    headers: {
      Accept: 'application/json',
    },
    mode: 'cors',
  }).catch(() => null)
}
