import toast from "react-hot-toast";

interface ApiResponse<T = any> {
  message: string;
  data: T;
  state: number;
  time: number;
  errorCode: number;
  resultType: number;
}

class ApiService {
  apiUrl = import.meta.env.VITE_API_URL;
  private baseURL = this.apiUrl;
  private token: string | null = null;

  constructor() {
    // Initialize token from localStorage
    this.initializeToken();
  }

  private initializeToken() {
    try {
      const savedToken = localStorage.getItem("auth_token");
      if (savedToken) {
        const tokenData = JSON.parse(savedToken);
        this.token = tokenData.accessToken;
      }
    } catch (error) {
      console.error("Error initializing token:", error);
    }
  }

  public setToken(token: string) {
    this.token = token;
  }

  public clearToken() {
    this.token = null;
  }

  private handleSessionExpired(message?: string) {
    this.clearToken();
    localStorage.removeItem("auth_token");
    localStorage.removeItem("auth_user");
    try {
      sessionStorage.setItem("sessionExpired", "1");
    } catch {}
    if (message) {
      toast.error(message);
    }
    window.location.href = "/login";
  }

  private async request<T = any>(
    endpoint: string,
    options: RequestInit = {},
  ): Promise<ApiResponse<T>> {
    const url = `${this.baseURL}${endpoint}`;

    const defaultHeaders: HeadersInit = {
      "Content-Type": "application/json",
    };

    // Add authorization header if token exists
    if (this.token) {
      defaultHeaders.Authorization = `Bearer ${this.token}`;
    }

    const config: RequestInit = {
      ...options,
      headers: {
        ...defaultHeaders,
        ...options.headers,
      },
    };

    try {
      const response = await fetch(url, config);
      const data: ApiResponse<T> = await response.json();

      if (data.errorCode === 301) {
        this.handleSessionExpired("نشست شما منقضی شده است. لطفا دوباره وارد شوید.");
        throw new Error(data.message || "Session expired");
      }

      // Handle different response states
      if (!response.ok) {
        throw new Error(
          data.message || `HTTP error! status: ${response.status}`,
        );
      }

      if (data.state !== 0) {
        throw new Error(data.message || "API error occurred");
      }

      return data;
    } catch (error) {
      console.error("API request failed:", error);

      // Handle network errors (propagate up; UI decides how to toast)
      if (error instanceof TypeError && error.message.includes("fetch")) {
        const err = Object.assign(new Error("شبکه در دسترس نیست"), {
          code: "NETWORK_ERROR",
        });
        throw err;
      }

      // Handle authentication errors
      if (error instanceof Error && error.message.includes("401")) {
        this.handleSessionExpired();
        throw error;
      }

      throw error;
    }
  }

  // POST to external absolute endpoint while reusing token handling
  public async postAbsolute<T = any>(
    fullUrl: string,
    data?: any,
  ): Promise<ApiResponse<T>> {
    const defaultHeaders: HeadersInit = {
      "Content-Type": "application/json;charset=UTF-8",
    };

    if (this.token) {
      defaultHeaders.Authorization = `Bearer ${this.token}`;
    }

    const config: RequestInit = {
      method: "POST",
      headers: defaultHeaders,
      body: data ? JSON.stringify(data) : undefined,
    };

    try {
      const response = await fetch(fullUrl, config);
      const apiData: ApiResponse<T> = await response.json();

      if (apiData.errorCode === 301) {
        this.handleSessionExpired("نشست شما منقضی شده است. لطفا دوباره وارد شوید.");
        throw new Error(apiData.message || "Session expired");
      }

      if (!response.ok) {
        throw new Error(apiData?.message || `HTTP error! status: ${response.status}`);
      }

      if (typeof apiData?.state !== "undefined" && apiData.state !== 0) {
        throw new Error(apiData.message || "API error occurred");
      }

      return apiData;
    } catch (error) {
      console.error("API absolute POST failed:", error);
      throw error as Error;
    }
  }

  // Innovation process function call wrapper
  public async call<T = any>(payload: any) {
    const url = "https://inogen-back.pelekan.org/api/call";
    return this.postAbsolute<T>(url, payload);
  }

  // GET request
  public async get<T = any>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: "GET",
    });
  }

  // POST request
  public async post<T = any>(
    endpoint: string,
    data?: any,
  ): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: "POST",
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  // PUT request
  public async put<T = any>(
    endpoint: string,
    data?: any,
  ): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: "PUT",
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  // DELETE request
  public async delete<T = any>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: "DELETE",
    });
  }

  // PATCH request
  public async patch<T = any>(
    endpoint: string,
    data?: any,
  ): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: "PATCH",
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  // Authentication methods
  public async login(username: string, password: string) {
    try {
      const response = await this.post("/login", {
        username,
        password,
      });

      if (response.state === 0) {
        const parsedData = JSON.parse(response.data);
        this.setToken(parsedData.Token.AccessToken);
        return {
          success: true,
          data: parsedData,
          message: response.message,
        };
      }

      return {
        success: false,
        message: response.message || "ورود ناموفق",
      };
    } catch (error) {
      return {
        success: false,
        message: error instanceof Error ? error.message : "خطای غیرمنتظره",
      };
    }
  }

  public async logout() {
    try {
      // Call logout endpoint if it exists
      await this.post("/logout");
    } catch (error) {
      console.error("Logout API call failed:", error);
    } finally {
      // Clear token regardless of API call success
      this.clearToken();
      localStorage.removeItem("auth_token");
      localStorage.removeItem("auth_user");
    }
  }

  // Profile methods
  public async getProfile() {
    return this.get("/profile");
  }

  public async updateProfile(data: any) {
    return this.put("/profile", data);
  }

  // Select method for dynamic data queries
  public async select(
    data:
      | {
          ProcessName: string;
          OutputFields: string[];
          Pagination: { PageNumber: number; PageSize: number };
          Sorts: [string, string][];
          Conditions: any[];
        }
      | any,
  ) {
    return this.post("/select", data);
  }

  // Projects methods
  public async getProjects() {
    return this.get("/projects");
  }

  // Dashboard methods
  public async getDashboardStats() {
    return this.get("/dashboard/stats");
  }

  public async getDashboardRecentActivity() {
    return this.get("/dashboard/recent-activity");
  }

  // File upload method
  public async uploadFile(file: File, endpoint: string = "/upload") {
    const formData = new FormData();
    formData.append("file", file);

    const config: RequestInit = {
      method: "POST",
      headers: this.token ? { Authorization: `Bearer ${this.token}` } : {},
      body: formData,
    };

    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, config);
      const data = await response.json();

      if (!response.ok) {
        throw new Error(
          data.message || `HTTP error! status: ${response.status}`,
        );
      }

      return data;
    } catch (error) {
      console.error("File upload failed:", error);
      throw error;
    }
  }
}

// Create and export a singleton instance
const apiService = new ApiService();

export default apiService;

// Export types for use in components
export type { ApiResponse };
