import type {
  AllowedModule,
  EnabledStatus,
  RoleCode,
  SecurityLevel,
} from "../../shared/api/enums";
import {
  AllowedModule as AllowedModuleValues,
  EnabledStatus as EnabledStatusValues,
  RoleCode as RoleCodeValues,
  SecurityLevel as SecurityLevelValues,
} from "../../shared/api/enums";
import type { Id } from "../../shared/api/types";

export interface LoginRequest {
  username: string;
  password: string;
  keepSignedIn: boolean;
}

export interface UserSummary {
  id: Id;
  username: string;
  realName: string;
  organizationId: Id | null;
  organizationName: string | null;
  roleCode: RoleCode;
  securityLevel: SecurityLevel;
  status: EnabledStatus;
  allowedModules: AllowedModule[];
}

export interface LoginResponseData {
  accessToken: string;
  tokenType: "Bearer";
  expiresIn: number;
  user: UserSummary;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return !!value && typeof value === "object";
}

function isId(value: unknown): value is Id {
  return typeof value === "string" && /^[0-9]+$/.test(value);
}

function isValueOf<T extends Record<string, string>>(
  values: T,
  value: unknown,
): value is T[keyof T] {
  return (
    typeof value === "string" &&
    (Object.values(values) as string[]).includes(value)
  );
}

export function isUserSummary(value: unknown): value is UserSummary {
  if (!isRecord(value)) return false;
  return (
    isId(value.id) &&
    typeof value.username === "string" &&
    typeof value.realName === "string" &&
    (value.organizationId === null || isId(value.organizationId)) &&
    (value.organizationName === null || typeof value.organizationName === "string") &&
    isValueOf(RoleCodeValues, value.roleCode) &&
    isValueOf(SecurityLevelValues, value.securityLevel) &&
    isValueOf(EnabledStatusValues, value.status) &&
    Array.isArray(value.allowedModules) &&
    value.allowedModules.every((module) =>
      isValueOf(AllowedModuleValues, module),
    )
  );
}

export function isLoginResponseData(
  value: unknown,
): value is LoginResponseData {
  if (!isRecord(value)) return false;
  return (
    typeof value.accessToken === "string" &&
    value.accessToken.length > 0 &&
    value.tokenType === "Bearer" &&
    typeof value.expiresIn === "number" &&
    Number.isFinite(value.expiresIn) &&
    value.expiresIn > 0 &&
    isUserSummary(value.user)
  );
}
