/**
 * Authentication API Service
 *
 * Handles all authentication-related API calls:
 * - Pre-login (password verification + send verification code)
 * - Resend verification code
 * - Verify login (code verification + get tokens)
 * - Google login
 */
import { ApiResponse, ApisauceInstance, create } from "apisauce"

import Config from "@/config"

import { getGeneralApiProblem, GeneralApiProblem } from "./apiProblem"
import type {
  BindNewEmailRequest,
  BindNewEmailResponse,
  ChangePasswordRequest,
  ChangePasswordResponse,
  ForgotPasswordRequest,
  ForgotPasswordResponse,
  GetLoginHistoryParams,
  GetLoginHistoryResponse,
  GetProfileResponse,
  GetSessionCountResponse,
  GetSessionsParams,
  GetSessionsResponse,
  GoogleLoginRequest,
  GoogleLoginResponse,
  LogoutResponse,
  PreLoginRequest,
  PreLoginResponse,
  PreRegisterRequest,
  PreRegisterResponse,
  RefreshTokenRequest,
  RefreshTokenResponse,
  ResendCodeRequest,
  ResendCodeResponse,
  ResendForgotPasswordRequest,
  ResendForgotPasswordResponse,
  ResendRegisterCodeRequest,
  ResendRegisterCodeResponse,
  ResetPasswordRequest,
  ResetPasswordResponse,
  RevokeOtherSessionsResponse,
  RevokeSessionResponse,
  SendEmailCodeRequest,
  SendEmailCodeResponse,
  UpdateProfileRequest,
  UpdateProfileResponse,
  VerifyCurrentEmailRequest,
  VerifyCurrentEmailResponse,
  VerifyLoginRequest,
  VerifyLoginResponse,
  VerifyRegisterRequest,
  VerifyRegisterResponse,
} from "./authTypes"

const AUTH_API_CONFIG = {
  url: Config.AUTH_API_URL || "https://auth.upay01.com",
  timeout: 15000,
}

/**
 * Auth API class for handling authentication requests
 */
export class AuthApi {
  apisauce: ApisauceInstance

  constructor() {
    this.apisauce = create({
      baseURL: AUTH_API_CONFIG.url,
      timeout: AUTH_API_CONFIG.timeout,
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
    })
  }

  /**
   * Pre-login: Verify password and send verification code
   */
  async preLogin(
    email: string,
    password: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: PreLoginResponse } | GeneralApiProblem> {
    const payload: PreLoginRequest = { email, password }
    if (language) payload.language = language

    const response: ApiResponse<PreLoginResponse> = await this.apisauce.post(
      "/api/auth/pre-login",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth preLogin error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Resend verification code
   */
  async resendCode(
    email: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: ResendCodeResponse } | GeneralApiProblem> {
    const payload: ResendCodeRequest = { email }
    if (language) payload.language = language

    const response: ApiResponse<ResendCodeResponse> = await this.apisauce.post(
      "/api/auth/pre-login/resend",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth resendCode error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Verify login: Verify code and get tokens
   */
  async verifyLogin(
    email: string,
    code: string,
  ): Promise<{ kind: "ok"; data: VerifyLoginResponse } | GeneralApiProblem> {
    const payload: VerifyLoginRequest = { email, code }

    const response: ApiResponse<VerifyLoginResponse> = await this.apisauce.post(
      "/api/auth/login/verify",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth verifyLogin error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Google login
   */
  async googleLogin(
    idToken: string,
    referralCode?: string,
  ): Promise<{ kind: "ok"; data: GoogleLoginResponse } | GeneralApiProblem> {
    const payload: GoogleLoginRequest = { idToken }
    if (referralCode) payload.referralCode = referralCode

    const response: ApiResponse<GoogleLoginResponse> = await this.apisauce.post(
      "/api/auth/google-login",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth googleLogin error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Pre-register: Validate data and send verification code
   */
  async preRegister(
    username: string,
    password: string,
    email: string,
    nickname?: string,
    referralCode?: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: PreRegisterResponse } | GeneralApiProblem> {
    const payload: PreRegisterRequest = { username, password, email }
    if (nickname) payload.nickname = nickname
    if (referralCode) payload.referralCode = referralCode
    if (language) payload.language = language

    const response: ApiResponse<PreRegisterResponse> = await this.apisauce.post(
      "/api/auth/pre-register",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth preRegister error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Resend register verification code
   */
  async resendRegisterCode(
    email: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: ResendRegisterCodeResponse } | GeneralApiProblem> {
    const payload: ResendRegisterCodeRequest = { email }
    if (language) payload.language = language

    const response: ApiResponse<ResendRegisterCodeResponse> = await this.apisauce.post(
      "/api/auth/pre-register/resend",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth resendRegisterCode error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Verify register: Verify code and create user
   */
  async verifyRegister(
    email: string,
    code: string,
  ): Promise<{ kind: "ok"; data: VerifyRegisterResponse } | GeneralApiProblem> {
    const payload: VerifyRegisterRequest = { email, code }

    const response: ApiResponse<VerifyRegisterResponse> = await this.apisauce.post(
      "/api/auth/register/verify",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth verifyRegister error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Forgot password: Send verification code
   */
  async forgotPassword(
    email: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: ForgotPasswordResponse } | GeneralApiProblem> {
    const payload: ForgotPasswordRequest = { email }
    if (language) payload.language = language

    const response: ApiResponse<ForgotPasswordResponse> = await this.apisauce.post(
      "/api/auth/forgot-password",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth forgotPassword error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Resend forgot password verification code
   */
  async resendForgotPasswordCode(
    email: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: ResendForgotPasswordResponse } | GeneralApiProblem> {
    const payload: ResendForgotPasswordRequest = { email }
    if (language) payload.language = language

    const response: ApiResponse<ResendForgotPasswordResponse> = await this.apisauce.post(
      "/api/auth/forgot-password/resend",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth resendForgotPasswordCode error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Reset password: Verify code and set new password
   */
  async resetPassword(
    email: string,
    code: string,
    newPassword: string,
  ): Promise<{ kind: "ok"; data: ResetPasswordResponse } | GeneralApiProblem> {
    const payload: ResetPasswordRequest = { email, code, newPassword }

    const response: ApiResponse<ResetPasswordResponse> = await this.apisauce.post(
      "/api/auth/reset-password",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth resetPassword error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Logout: Revoke token
   */
  async logoutApi(
    accessToken: string,
  ): Promise<{ kind: "ok"; data: LogoutResponse } | GeneralApiProblem> {
    const response: ApiResponse<LogoutResponse> = await this.apisauce.post(
      "/api/auth/logout",
      {},
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth logout error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  // ============================================
  // Profile APIs
  // ============================================

  /**
   * Get user profile
   */
  async getProfile(
    accessToken: string,
  ): Promise<{ kind: "ok"; data: GetProfileResponse } | GeneralApiProblem> {
    const response: ApiResponse<GetProfileResponse> = await this.apisauce.get(
      "/api/auth/profile",
      {},
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth getProfile error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Update user profile
   */
  async updateProfile(
    accessToken: string,
    payload: UpdateProfileRequest,
  ): Promise<{ kind: "ok"; data: UpdateProfileResponse } | GeneralApiProblem> {
    const response: ApiResponse<UpdateProfileResponse> = await this.apisauce.put(
      "/api/auth/profile",
      payload,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth updateProfile error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  // ============================================
  // Password APIs
  // ============================================

  /**
   * Change password
   */
  async changePassword(
    accessToken: string,
    payload: ChangePasswordRequest,
  ): Promise<{ kind: "ok"; data: ChangePasswordResponse } | GeneralApiProblem> {
    const response: ApiResponse<ChangePasswordResponse> = await this.apisauce.post(
      "/api/auth/change-password",
      payload,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth changePassword error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  // ============================================
  // Token APIs
  // ============================================

  /**
   * Refresh access token
   */
  async refreshToken(
    refreshToken: string,
  ): Promise<{ kind: "ok"; data: RefreshTokenResponse } | GeneralApiProblem> {
    const payload: RefreshTokenRequest = { refreshToken }

    const response: ApiResponse<RefreshTokenResponse> = await this.apisauce.post(
      "/api/auth/refresh-token",
      payload,
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth refreshToken error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  // ============================================
  // Email APIs
  // ============================================

  /**
   * Send email verification code (for changing email)
   */
  async sendEmailCode(
    accessToken: string,
    email: string,
    language?: string,
  ): Promise<{ kind: "ok"; data: SendEmailCodeResponse } | GeneralApiProblem> {
    const payload: SendEmailCodeRequest = { email }
    if (language) payload.language = language

    const response: ApiResponse<SendEmailCodeResponse> = await this.apisauce.post(
      "/api/email/send-verification-code",
      payload,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth sendEmailCode error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Verify current email (Step 1 of email change)
   */
  async verifyCurrentEmail(
    accessToken: string,
    currentCode: string,
  ): Promise<{ kind: "ok"; data: VerifyCurrentEmailResponse } | GeneralApiProblem> {
    const payload: VerifyCurrentEmailRequest = {
      action: "verify-current",
      currentCode,
    }

    const response: ApiResponse<VerifyCurrentEmailResponse> = await this.apisauce.post(
      "/api/email/change",
      payload,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth verifyCurrentEmail error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Bind new email (Step 2 of email change)
   */
  async bindNewEmail(
    accessToken: string,
    newEmail: string,
    newCode: string,
  ): Promise<{ kind: "ok"; data: BindNewEmailResponse } | GeneralApiProblem> {
    const payload: BindNewEmailRequest = {
      action: "bind-new",
      newEmail,
      newCode,
    }

    const response: ApiResponse<BindNewEmailResponse> = await this.apisauce.post(
      "/api/email/change",
      payload,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth bindNewEmail error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  // ============================================
  // Session Management APIs
  // ============================================

  /**
   * Get sessions/devices list
   */
  async getSessions(
    accessToken: string,
    params?: GetSessionsParams,
  ): Promise<{ kind: "ok"; data: GetSessionsResponse } | GeneralApiProblem> {
    const response: ApiResponse<GetSessionsResponse> = await this.apisauce.get(
      "/api/sessions",
      params,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth getSessions error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Get active session count
   */
  async getSessionCount(
    accessToken: string,
  ): Promise<{ kind: "ok"; data: GetSessionCountResponse } | GeneralApiProblem> {
    const response: ApiResponse<GetSessionCountResponse> = await this.apisauce.get(
      "/api/sessions/count",
      {},
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth getSessionCount error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Get login history
   */
  async getLoginHistory(
    accessToken: string,
    params?: GetLoginHistoryParams,
  ): Promise<{ kind: "ok"; data: GetLoginHistoryResponse } | GeneralApiProblem> {
    const response: ApiResponse<GetLoginHistoryResponse> = await this.apisauce.get(
      "/api/sessions/history",
      params,
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth getLoginHistory error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Revoke a specific session (remote logout device)
   */
  async revokeSession(
    accessToken: string,
    sessionId: string,
  ): Promise<{ kind: "ok"; data: RevokeSessionResponse } | GeneralApiProblem> {
    const response: ApiResponse<RevokeSessionResponse> = await this.apisauce.delete(
      `/api/sessions/${sessionId}`,
      {},
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth revokeSession error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }

  /**
   * Revoke all other sessions (logout all other devices)
   */
  async revokeOtherSessions(
    accessToken: string,
  ): Promise<{ kind: "ok"; data: RevokeOtherSessionsResponse } | GeneralApiProblem> {
    const response: ApiResponse<RevokeOtherSessionsResponse> = await this.apisauce.post(
      "/api/sessions/revoke-others",
      {},
      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    )

    if (!response.ok) {
      const problem = getGeneralApiProblem(response)
      if (problem) return problem
    }

    try {
      const data = response.data
      if (!data) return { kind: "bad-data" }
      return { kind: "ok", data }
    } catch (e) {
      if (__DEV__ && e instanceof Error) {
        console.error(`Auth revokeOtherSessions error: ${e.message}`)
      }
      return { kind: "bad-data" }
    }
  }
}

// Singleton instance
export const authApi = new AuthApi()
