import type { AuthorizationServer } from "oauth4webapi"
import { AuthOperationsFromCollectionSlug, Collection, PayloadRequest, StringKeyOf } from "payload"

export enum ErrorKind {
  NotFound = "NotFound",
  InternalServer = "InternalServer",
  BadRequest = "BadRequest",
  NotAuthorized = "NotAuthorized",
  NotAuthenticated = "NotAuthenticated",
  Conflict = "Conflict",
}

export enum SuccessKind {
  Created = "Created",
  Updated = "Updated",
  Retrieved = "Retrieved",
  Deleted = "Deleted",
}
export interface AuthPluginOutput {
  message: string
  kind: ErrorKind | SuccessKind
  data: unknown
  isSuccess: boolean
  isError: boolean
}

/**
 * Generic OAuth provider callback output
 *
 * @interface OAuthProviderOutput
 * @internal
 */
interface OAuthProviderOutput {
  /**
   * OAuth Provider ID. Usually the slugified provider name
   *
   * @type {string}
   */
  id: string
  /**
   * OAuth provider name. For example Google, Apple
   *
   * @type {string}
   */
  name: string
  /**
   * Scope of account attributes to request from the provider
   *
   * @type {string}
   */
  scope: string

  /**
   * Email Domain to create custom email addresses
   * @type {string}
   */
  emailDomain?: string | undefined

  /**
   * Profile callback that returns account information requried to link with users
   *
   * @type {(
   *     profile: Record<string, string | number | boolean | object>,
   *   ) => AccountInfo}
   */
  profile: (
    profile: Record<string, string | number | boolean | object>,
  ) => AccountInfo
}

export interface OAuthBaseProviderConfig {
  client_id: string
  client_secret?: string
  /*
   * Oauth provider Client Type
   */
  client_auth_type?: "client_secret_basic" | "client_secret_post"
  /*
   * Additional parameters you would like to add to query for the provider
   */
  params?: Record<string, string>
  /**
   * Override default scope of the provider
   */
  overrideScope?: string | undefined

}

export interface OIDCProviderConfig
  extends OAuthProviderOutput,
  OAuthBaseProviderConfig {
  issuer: string
  algorithm: "oidc"
  kind: "oauth"
  skip_email_verification?: boolean | undefined
}

export interface OAuth2ProviderConfig
  extends OAuthProviderOutput,
  OAuthBaseProviderConfig {
  authorization_server: AuthorizationServer
  algorithm: "oauth2"
  kind: "oauth"
}

export type OAuthProviderConfig = OIDCProviderConfig | OAuth2ProviderConfig

export interface AccountInfo {
  sub: string
  name: string
  picture: string
  email: string
  passKey?: {
    credentialId: string
    publicKey?: Uint8Array
    counter: number
    transports?: string[]
    deviceType: string
    backedUp: boolean
  }
  access_token?: string
  refresh_token?: string
  expires_in?: number
}

export type PasswordProviderConfig = {
  id: string
  kind: "password"
  emailTemplates: {
    forgotPassword: any
  }
  // name: string
  // verfiyEmail?: boolean
  // passwordless?: boolean
  // mfa?: "OTP" | "TOTP" | "None"
  // signinCallback?: () => void
  // signupCallback?: () => void
}

export interface CredentialsAccountInfo {
  name: string
  email: string
}

export type PasskeyProviderConfig = {
  id: string
  kind: "passkey"
}

export type ProvidersConfig =
  | OAuthProviderConfig
  | PasskeyProviderConfig
  | PasswordProviderConfig

export type AuthenticationStrategy = "Cookie"

export type UserSession = {
  createdAt: Date | string
  expiresAt: Date | string
  id: string
}

export interface PayloadTypesShape {
  auth: Record<string, unknown>
  blocks: Record<string, unknown>
  collections: Record<string, unknown>
  collectionsJoins: Record<string, unknown>
  collectionsSelect: Record<string, unknown>
  db: { defaultIDType: unknown }
  fallbackLocale: unknown
  globals: Record<string, unknown>
  globalsSelect: Record<string, unknown>
  jobs: unknown
  locale: unknown
  user: unknown
  widgets?: Record<string, unknown>
}

export type AuthCollectionSlug<T extends PayloadTypesShape = any> = StringKeyOf<T['auth']>

export type Arguments<TSlug extends AuthCollectionSlug> = {
  collection: Collection
  data: AuthOperationsFromCollectionSlug<TSlug>['login']
  depth?: number
  overrideAccess?: boolean
  req: PayloadRequest
  showHiddenFields?: boolean
}
