import axios, { type AxiosInstance, AxiosError } from "axios";
import type {
  User,
  Hook,
  WhatsAppAccount,
  WhatsAppAccountConfig,
  PhoneNumberListResponse,
  BusinessProfile,
  BusinessProfileUpdateRequest,
  TemplateListResponse,
  TemplateUploadRequest,
  FlowListResponse,
  CatalogListResponse,
  EventLog,
  APIKey,
  LoginRequest,
  LoginResponse,
  MessageCacheListResponse,
  MessageCacheStats,
  SystemStats,
  WhatsAppAccountRuntimeStatus,
} from "../types";

function normalizePath(path: string): string {
  const collapsed = (path || "/").replace(/\/{2,}/g, "/");
  if (collapsed.length > 1 && collapsed.endsWith("/")) {
    return collapsed.slice(0, -1);
  }
  return collapsed || "/";
}

function getAppBasePath(pathname: string): string {
  const normalized = normalizePath(pathname);
  const match = normalized.match(/^(.*)\/ui(?:\/|$)/);
  if (!match) return "";
  const prefix = match[1] || "";
  return prefix === "/" ? "" : prefix;
}

function getApiBaseUrl(): string {
  if (import.meta.env.VITE_API_URL)
    return import.meta.env.VITE_API_URL.replace(/\/+$/, "");
  const { hostname, protocol, port } = window.location;
  const appBasePath = getAppBasePath(window.location.pathname);
  if (hostname === "localhost" || hostname === "127.0.0.1")
    return "http://localhost:8080";
  return `${protocol}//${hostname}${port ? `:${port}` : ""}${appBasePath}`.replace(
    /\/+$/,
    "",
  );
}

const API_BASE_URL = getApiBaseUrl();
const APP_BASE_PATH = getAppBasePath(window.location.pathname);
const LOGIN_API_PATH = "/api/v1/auth/login";
const LOGIN_UI_PATH = `${APP_BASE_PATH}/ui/login`.replace(/\/{2,}/g, "/");

function getNormalizedPathFromURL(input: string): string {
  if (!input) return "/";
  try {
    return normalizePath(new URL(input, window.location.origin).pathname);
  } catch {
    const withoutQuery = input.split("?")[0]?.split("#")[0] || "/";
    return normalizePath(withoutQuery);
  }
}

function normalizeUser(raw: unknown): User | null {
  if (!raw || typeof raw !== "object") return null;
  const value = raw as Record<string, unknown>;

  const resolvedUsername =
    (typeof value.username === "string" && value.username) ||
    (typeof value.user_name === "string" && value.user_name) ||
    (typeof value.full_name === "string" && value.full_name) ||
    (typeof value.email === "string" && value.email.split("@")[0]) ||
    "User";

  const resolvedRole =
    (typeof value.role === "string" && value.role) ||
    (Array.isArray(value.roles) &&
      typeof value.roles[0] === "string" &&
      value.roles[0]) ||
    "user";

  const claims =
    value.claims && typeof value.claims === "object"
      ? (value.claims as Record<string, unknown>)
      : null;

  const resolvedID =
    (typeof value.id === "string" && value.id) ||
    (typeof value.user_id === "string" && value.user_id) ||
    (claims && typeof claims.user_id === "string" && claims.user_id) ||
    "0";

  const normalized: User = {
    id: resolvedID,
    username: resolvedUsername,
    email: typeof value.email === "string" ? value.email : "",
    full_name:
      typeof value.full_name === "string" ? value.full_name : undefined,
    role: resolvedRole === "admin" ? "admin" : "user",
    active: typeof value.active === "boolean" ? value.active : true,
    created_at: typeof value.created_at === "string" ? value.created_at : "",
    updated_at: typeof value.updated_at === "string" ? value.updated_at : "",
  };

  return normalized;
}

class ApiClient {
  private client: AxiosInstance;

  constructor() {
    this.client = axios.create({
      baseURL: API_BASE_URL,
      headers: {
        "Content-Type": "application/json",
      },
    });

    // Request interceptor to add auth token
    this.client.interceptors.request.use((config) => {
      const token = this.getToken();
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    });

    // Response interceptor for error handling
    this.client.interceptors.response.use(
      (response) => response,
      (error: AxiosError) => {
        if (error.response?.status === 401) {
          const requestPath = getNormalizedPathFromURL(error.config?.url || "");
          const currentPath = normalizePath(window.location.pathname);
          const isLoginRequest =
            requestPath === LOGIN_API_PATH ||
            requestPath.endsWith(LOGIN_API_PATH);
          const isLoginPage = currentPath === LOGIN_UI_PATH;
          const isV1APIRequest = requestPath.startsWith("/api/v1/");

          // Keep failed login attempts on the same page.
          // Only force logout for JWT-protected API v1 requests.
          if (isV1APIRequest && !isLoginRequest && !isLoginPage) {
            this.clearAuth();
            window.location.href = LOGIN_UI_PATH;
          }
        }
        return Promise.reject(error);
      },
    );
  }

  // Token management
  private getToken(): string | null {
    return localStorage.getItem("auth_token");
  }

  private setToken(token: string): void {
    localStorage.setItem("auth_token", token);
  }

  private clearAuth(): void {
    localStorage.removeItem("auth_token");
    localStorage.removeItem("user");
  }

  // Auth endpoints
  async login(credentials: LoginRequest): Promise<LoginResponse> {
    const { data } = await this.client.post<LoginResponse>(
      LOGIN_API_PATH,
      credentials,
    );
    if (data.token) {
      this.setToken(data.token);
      const normalizedUser = normalizeUser(data.user);
      if (normalizedUser) {
        localStorage.setItem("user", JSON.stringify(normalizedUser));
        data.user = normalizedUser;
      }
    }
    return data;
  }

  async logout(): Promise<void> {
    try {
      await this.client.post("/api/v1/auth/logout");
    } finally {
      this.clearAuth();
    }
  }

  getCurrentUser(): User | null {
    const userStr = localStorage.getItem("user");
    if (!userStr) return null;
    try {
      return normalizeUser(JSON.parse(userStr));
    } catch {
      return null;
    }
  }

  isAuthenticated(): boolean {
    return !!this.getToken();
  }

  // Unified query endpoint
  async query(request: {
    action: "list" | "get" | "create" | "update" | "delete";
    table: string;
    id?: string;
    data?: Record<string, any>;
    filters?: Record<string, any>;
    limit?: number;
    offset?: number;
  }): Promise<any> {
    const { data } = await this.client.post("/api/v1/query", request);
    return data;
  }

  // Users API
  async getUsers(): Promise<User[]> {
    const { data } = await this.client.get<User[]>("/api/v1/users");
    return data;
  }

  async getUser(id: string): Promise<User> {
    const { data } = await this.client.get<User>(`/api/v1/users/${id}`);
    return data;
  }

  async createUser(user: Partial<User>): Promise<User> {
    const { data } = await this.client.post<User>("/api/v1/users", user);
    return data;
  }

  async updateUser(id: string, user: Partial<User>): Promise<User> {
    const { data } = await this.client.put<User>(`/api/v1/users/${id}`, user);
    return data;
  }

  async deleteUser(id: string): Promise<void> {
    await this.client.delete(`/api/v1/users/${id}`);
  }

  // Hooks API
  async getHooks(): Promise<Hook[]> {
    const { data } = await this.client.get<Hook[]>("/api/v1/hooks");
    return data;
  }

  async getHook(id: string): Promise<Hook> {
    const { data } = await this.client.get<Hook>(`/api/v1/hooks/${id}`);
    return data;
  }

  async createHook(hook: Partial<Hook>): Promise<Hook> {
    const { data } = await this.client.post<Hook>("/api/v1/hooks", hook);
    return data;
  }

  async updateHook(id: string, hook: Partial<Hook>): Promise<Hook> {
    const { data } = await this.client.put<Hook>(`/api/v1/hooks/${id}`, hook);
    return data;
  }

  async deleteHook(id: string): Promise<void> {
    await this.client.delete(`/api/v1/hooks/${id}`);
  }

  // WhatsApp Accounts API
  async getAccounts(): Promise<WhatsAppAccount[]> {
    const { data } = await this.client.get<WhatsAppAccount[]>(
      "/api/v1/whatsapp_accounts",
    );
    return data;
  }

  async getAccount(id: string): Promise<WhatsAppAccount> {
    const { data } = await this.client.get<WhatsAppAccount>(
      `/api/v1/whatsapp_accounts/${id}`,
    );
    return data;
  }

  async createAccount(
    account: Partial<WhatsAppAccount>,
  ): Promise<WhatsAppAccount> {
    const { data } = await this.client.post<WhatsAppAccount>(
      "/api/v1/whatsapp_accounts",
      account,
    );
    return data;
  }

  async updateAccount(
    id: string,
    account: Partial<WhatsAppAccount>,
  ): Promise<WhatsAppAccount> {
    const { data } = await this.client.put<WhatsAppAccount>(
      `/api/v1/whatsapp_accounts/${id}`,
      account,
    );
    return data;
  }

  async deleteAccount(id: string): Promise<void> {
    await this.client.delete(`/api/v1/whatsapp_accounts/${id}`);
  }

  async getAccountConfigs(): Promise<WhatsAppAccountConfig[]> {
    const { data } =
      await this.client.get<WhatsAppAccountConfig[]>("/api/accounts");
    return data;
  }

  async getAccountStatuses(): Promise<{
    statuses: WhatsAppAccountRuntimeStatus[];
  }> {
    const { data } = await this.client.get<{
      statuses: WhatsAppAccountRuntimeStatus[];
    }>("/api/accounts/status");
    return data;
  }

  async addAccountConfig(
    account: WhatsAppAccountConfig,
  ): Promise<{ status: string; account_id: string }> {
    const { data } = await this.client.post<{
      status: string;
      account_id: string;
    }>("/api/accounts/add", account);
    return data;
  }

  async updateAccountConfig(
    account: WhatsAppAccountConfig,
  ): Promise<{ status: string; account_id: string }> {
    const { data } = await this.client.post<{
      status: string;
      account_id: string;
    }>("/api/accounts/update", account);
    return data;
  }

  async removeAccountConfig(id: string): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/accounts/remove",
      { id },
    );
    return data;
  }

  async sendPayload(
    endpoint: string,
    payload: Record<string, unknown>,
  ): Promise<{ status?: string; [key: string]: unknown }> {
    const { data } = await this.client.post<{
      status?: string;
      [key: string]: unknown;
    }>(endpoint, payload);
    return data;
  }

  // WhatsApp Business management API
  async listPhoneNumbers(accountId: string): Promise<PhoneNumberListResponse> {
    const { data } = await this.client.post<PhoneNumberListResponse>(
      "/api/phone-numbers",
      { account_id: accountId },
    );
    return data;
  }

  async requestVerificationCode(payload: {
    account_id: string;
    phone_number_id: string;
    code_method: "SMS" | "VOICE";
    language?: string;
  }): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/phone-numbers/request-code",
      payload,
    );
    return data;
  }

  async verifyPhoneCode(payload: {
    account_id: string;
    phone_number_id: string;
    code: string;
  }): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/phone-numbers/verify-code",
      payload,
    );
    return data;
  }

  async registerPhoneNumber(payload: {
    account_id: string;
    phone_number_id: string;
    pin: string;
  }): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/phone-numbers/register",
      payload,
    );
    return data;
  }

  async getBusinessProfile(accountId: string): Promise<BusinessProfile> {
    const { data } = await this.client.post<BusinessProfile>(
      "/api/business-profile",
      { account_id: accountId },
    );
    return data;
  }

  async updateBusinessProfile(
    payload: BusinessProfileUpdateRequest,
  ): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/business-profile/update",
      payload,
    );
    return data;
  }

  async listTemplates(accountId: string): Promise<TemplateListResponse> {
    const { data } = await this.client.post<TemplateListResponse>(
      "/api/templates",
      { account_id: accountId },
    );
    return data;
  }

  async uploadTemplate(
    payload: TemplateUploadRequest,
  ): Promise<Record<string, unknown>> {
    const { data } = await this.client.post<Record<string, unknown>>(
      "/api/templates/upload",
      payload,
    );
    return data;
  }

  async deleteTemplate(payload: {
    account_id: string;
    name: string;
    language: string;
  }): Promise<{ status: string }> {
    const { data } = await this.client.post<{ status: string }>(
      "/api/templates/delete",
      payload,
    );
    return data;
  }

  async listCatalogs(accountId: string): Promise<CatalogListResponse> {
    const { data } = await this.client.post<CatalogListResponse>(
      "/api/catalogs",
      { account_id: accountId },
    );
    return data;
  }

  async listFlows(accountId: string): Promise<FlowListResponse> {
    const { data } = await this.client.post<FlowListResponse>("/api/flows", {
      account_id: accountId,
    });
    return data;
  }

  // Event Logs API — uses RestHeadSpec native headers for server-side pagination/sorting
  async getEventLogs(params?: {
    limit?: number;
    offset?: number;
    sort?: string;
    search?: string;
  }): Promise<{
    data: EventLog[];
    meta: { total: number; limit: number; offset: number };
  }> {
    const headers: Record<string, string> = { "X-DetailApi": "true" };
    if (params?.sort) headers["X-Sort"] = params.sort;
    if (params?.limit) headers["X-Limit"] = String(params.limit);
    if (params?.offset !== undefined)
      headers["X-Offset"] = String(params.offset);
    if (params?.search) headers["X-SearchOp-Like-EventType"] = params.search;

    const { data } = await this.client.get<{
      data: EventLog[];
      meta: { total: number; limit: number; offset: number };
    }>("/api/v1/event_logs", { headers });
    return data;
  }

  // Message cache API
  async getMessageCacheEvents(params?: {
    limit?: number;
    offset?: number;
    eventType?: string;
  }): Promise<MessageCacheListResponse> {
    const searchParams = new URLSearchParams();
    if (params?.limit) searchParams.set("limit", String(params.limit));
    if (params?.offset !== undefined)
      searchParams.set("offset", String(params.offset));
    if (params?.eventType) searchParams.set("event_type", params.eventType);

    const query = searchParams.toString();
    const url = query ? `/api/cache?${query}` : "/api/cache";
    const { data } = await this.client.get<MessageCacheListResponse>(url);
    return data;
  }

  async getMessageCacheStats(): Promise<MessageCacheStats> {
    const { data } = await this.client.get<MessageCacheStats>(
      "/api/v1/cache/stats",
    );
    return data;
  }

  async replayCachedEvent(
    id: string,
  ): Promise<{ success: boolean; event_id: string; message: string }> {
    const { data } = await this.client.post<{
      success: boolean;
      event_id: string;
      message: string;
    }>(`/api/cache/event/replay?id=${encodeURIComponent(id)}`);
    return data;
  }

  async deleteCachedEvent(
    id: string,
  ): Promise<{ success: boolean; event_id: string; message: string }> {
    const { data } = await this.client.delete<{
      success: boolean;
      event_id: string;
      message: string;
    }>(`/api/cache/event/delete?id=${encodeURIComponent(id)}`);
    return data;
  }

  async replayAllCachedEvents(): Promise<{
    success: boolean;
    replayed: number;
    delivered: number;
    failed: number;
    remaining_cached: number;
  }> {
    const { data } = await this.client.post<{
      success: boolean;
      replayed: number;
      delivered: number;
      failed: number;
      remaining_cached: number;
    }>("/api/cache/replay");
    return data;
  }

  async clearMessageCache(): Promise<{
    success: boolean;
    cleared: number;
    message: string;
  }> {
    const { data } = await this.client.delete<{
      success: boolean;
      cleared: number;
      message: string;
    }>("/api/cache/clear?confirm=true");
    return data;
  }

  async getQRCode(accountId: string): Promise<Blob> {
    const { data } = await this.client.get<Blob>(
      `/api/qr/${encodeURIComponent(accountId)}`,
      {
        responseType: "blob",
      },
    );
    return data;
  }

  // API Keys API
  async getAPIKeys(): Promise<APIKey[]> {
    const { data } = await this.client.get<APIKey[]>("/api/v1/api_keys");
    return data;
  }

  async createAPIKey(apiKey: Partial<APIKey>): Promise<APIKey> {
    const { data } = await this.client.post<APIKey>("/api/v1/api_keys", apiKey);
    return data;
  }

  async deleteAPIKey(id: string): Promise<void> {
    await this.client.delete(`/api/v1/api_keys/${id}`);
  }

  // Health check
  async healthCheck(): Promise<{ status: string }> {
    const { data } = await this.client.get<{ status: string }>("/health");
    return data;
  }

  async getSystemStats(): Promise<SystemStats> {
    const { data } = await this.client.get<SystemStats>("/api/v1/system/stats");
    return data;
  }
}

export const apiClient = new ApiClient();
export default apiClient;
