import axios from 'axios';
import type { UserAccount, LoginResponse } from '@/types';

export interface GeoJSONFeatureCollection {
  type: 'FeatureCollection';
  features: Array<{ type: 'Feature'; properties?: Record<string, unknown>; geometry: { type: string; coordinates: unknown } }>;
}

// Use nginx proxy path when available, otherwise direct API
export const getApiBaseUrl = () => {
  if (typeof window === 'undefined') {
    // Server-side: use environment variable or default
    return process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8001';
  }
  
  // Client-side: check if we're behind nginx proxy
  const origin = window.location.origin;
  const port = window.location.port;
  const hostname = window.location.hostname;
  
  // Debug logging (can be removed in production if needed)
  if (process.env.NODE_ENV === 'development') {
    console.log('🔍 API Base URL Detection:', { hostname, port, origin });
  }
  
  // If accessing via nginx (port 7000) or same origin, use relative path
  // Check for 10.10.10.127 with port 7000 or no port (default http port)
  if (hostname === '10.10.10.127' && (port === '7000' || port === '')) {
    // if (process.env.NODE_ENV === 'development') {
    //   console.log('✅ Using nginx proxy path: /api');
    // }
    return '/api';  // Use nginx proxy path
  }
  
  // If accessing via network IP but different port, still use proxy if it's port 80 or 443
  if (hostname === '10.10.10.127') {
    // if (process.env.NODE_ENV === 'development') {
    //   console.log('✅ Using nginx proxy path for network access: /api');
    // }
    return '/api';  // Assume behind proxy for network access
  }
  
  // If accessing directly on port 3000, use direct API
  if (port === '3000' || hostname === 'localhost' || hostname === '127.0.0.1') {
    const directUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8001';
    // if (process.env.NODE_ENV === 'development') {
    //   console.log('✅ Using direct API URL:', directUrl);
    // }
    return directUrl;
  }
  
  // Default: use relative path (assumes behind proxy)
  // if (process.env.NODE_ENV === 'development') {
  //   console.log('✅ Using default nginx proxy path: /api');
  // }
  return '/api';
};

// Auth helpers (client-side only) – avoid calling /auth/me when not logged in
export function getStoredToken(): string | null {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem('access_token');
}

export function hasStoredToken(): boolean {
  return !!getStoredToken();
}

// Create axios instance with dynamic base URL
export const apiClient = axios.create({
  baseURL: '/api', // Default, will be overridden by interceptor
  headers: {
    'Content-Type': 'application/json',
  },
  timeout: 45000, // 45 second timeout to prevent hanging (auth/me can use longer per-request)
});

// Request interceptor - dynamically set base URL, add auth token, skip /auth/me when no token
apiClient.interceptors.request.use((config) => {
  const baseURL = getApiBaseUrl();
  config.baseURL = baseURL;

  if (typeof window !== 'undefined') {
    const token = localStorage.getItem('access_token');
    const isAuthMe = config.url === '/auth/me' || (typeof config.url === 'string' && config.url.endsWith('/auth/me'));
    if (isAuthMe && !token) {
      return Promise.reject(new Error('No access token'));
    }
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
  }
  return config;
});


// Response interceptor - on 401 try refresh token (industry standard), then retry or redirect to login
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    if (error.response?.status !== 401 || typeof window === 'undefined') {
      return Promise.reject(error);
    }
    // Avoid retry loop: if we already tried refresh for this request, go to login
    if (originalRequest._retried) {
      localStorage.removeItem('access_token');
      localStorage.removeItem('refresh_token');
      window.location.href = '/login';
      return Promise.reject(error);
    }
    const refreshToken = localStorage.getItem('refresh_token');
    if (!refreshToken) {
      localStorage.removeItem('access_token');
      window.location.href = '/login';
      return Promise.reject(error);
    }
    originalRequest._retried = true;
    try {
      const baseURL = getApiBaseUrl();
      const res = await axios.post<LoginResponse>(
        `${baseURL}/auth/refresh`,
        { refresh_token: refreshToken },
        { headers: { 'Content-Type': 'application/json' }, timeout: 10000 }
      );
      const data = res.data;
      localStorage.setItem('access_token', data.access_token);
      if (data.refresh_token) localStorage.setItem('refresh_token', data.refresh_token);
      originalRequest.headers.Authorization = `Bearer ${data.access_token}`;
      return apiClient.request(originalRequest);
    } catch {
      localStorage.removeItem('access_token');
      localStorage.removeItem('refresh_token');
      window.location.href = '/login';
      return Promise.reject(error);
    }
  }
);

// Auth API
export const authApi = {
  login: async (username: string, password: string) => {
    const formData = new URLSearchParams();
    formData.append('username', username);
    formData.append('password', password);

    const apiBaseUrl = getApiBaseUrl();
    const response = await axios.post(`${apiBaseUrl}/auth/login`, formData, {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      timeout: 15000, // 15s so login doesn't hang if backend is unreachable
    });
    return response.data;
  },
  
  logout: async () => {
    return apiClient.post('/auth/logout');
  },
  
  getCurrentUser: async (): Promise<UserAccount> => {
    if (!hasStoredToken()) {
      return Promise.reject(new Error('No access token'));
    }
    const response = await apiClient.get<UserAccount>('/auth/me');
    return response.data;
  },
};

export interface DataCentricFilters {
  year?: number;
  startYear?: number;
  endYear?: number;
  quarter?: string;
  month?: string;
  limit?: number;
  offset?: number;
  documentScope?: 'cofo_only' | 'all_documents';
  documentTypes?: string[];
  ownerType?: string | string[];
  ownerName?: string;
  ownerGender?: string | string[];
  ownershipType?: string | string[];
  ownershipCategory?: string | string[];
  propertyUniqueId?: string;
  issuanceDateFrom?: string;
  issuanceDateTo?: string;
  registrationDateFrom?: string;
  registrationDateTo?: string;
  referenceNumber?: string;
}

export const fetchDataCentricDashboard = async (filters?: DataCentricFilters) => {
  const params: Record<string, any> = {};
  const keyMap: Record<string, string> = {
    startYear: 'start_year',
    endYear: 'end_year',
    documentScope: 'document_scope',
    documentTypes: 'document_types',
    ownerType: 'owner_type',
    ownerName: 'owner_name',
    ownerGender: 'owner_gender',
    ownershipType: 'ownership_type',
    ownershipCategory: 'ownership_category',
    propertyUniqueId: 'property_unique_id',
    issuanceDateFrom: 'issuance_date_from',
    issuanceDateTo: 'issuance_date_to',
    registrationDateFrom: 'registration_date_from',
    registrationDateTo: 'registration_date_to',
    referenceNumber: 'reference_number',
  };

  if (filters) {
    Object.entries(filters).forEach(([key, value]) => {
      if (value !== undefined && value !== null && value !== '') {
        const paramKey = keyMap[key] ?? key;
        if (Array.isArray(value)) {
          const cleaned = value.filter((item) => item !== undefined && item !== null && `${item}`.trim() !== '');
          if (cleaned.length > 0) {
            params[paramKey] = cleaned;
          }
          return;
        }
        if (typeof value === 'string') {
          const trimmed = value.trim();
          if (trimmed) {
            params[paramKey] = trimmed;
          }
          return;
        }
        params[paramKey] = value;
      }
    });
  }

  const response = await apiClient.get('/analytics/data-centric', { params });
  return response.data;
};

export const fetchUsers = async (): Promise<UserAccount[]> => {
  const response = await apiClient.get<UserAccount[]>('/auth/users');
  return response.data;
};

export const updateUser = async (username: string, data: { password: string }): Promise<{ message: string }> => {
  const response = await apiClient.patch<{ message: string }>(`/auth/users/${encodeURIComponent(username)}`, data);
  return response.data;
};

export const deleteUser = async (username: string): Promise<{ message: string }> => {
  const response = await apiClient.delete<{ message: string }>(`/auth/users/${encodeURIComponent(username)}`);
  return response.data;
};

// Boundary Commission API
import type {
  Boundary,
  BoundarySearchResult,
  BoundaryDispute,
  DisputeSearchResult,
  BoundaryType,
  DisputeStatus,
} from '@/types/boundary';

export const boundaryApi = {
  // List boundaries with filters
  listBoundaries: async (params?: {
    boundary_number?: string;
    name?: string;
    boundary_type?: BoundaryType | string;
    state?: string;
    status?: string;
    limit?: number;
    offset?: number;
  }): Promise<Boundary[]> => {
    const response = await apiClient.get<Boundary[]>('/boundary/boundaries', { params });
    return response.data;
  },

  // Get boundary details
  getBoundary: async (boundaryNumber: string): Promise<BoundarySearchResult> => {
    const response = await apiClient.get<BoundarySearchResult>(`/boundary/boundaries/${boundaryNumber}`);
    return response.data;
  },

  // Create boundary
  createBoundary: async (boundary: Partial<Boundary>): Promise<Boundary> => {
    const response = await apiClient.post<Boundary>('/boundary/boundaries', boundary);
    return response.data;
  },

  // List disputes with filters
  listDisputes: async (params?: {
    dispute_number?: string;
    title?: string;
    status?: DisputeStatus | string;
    state?: string;
    priority?: string;
    claimant_a?: string;
    claimant_b?: string;
    limit?: number;
    offset?: number;
  }): Promise<BoundaryDispute[]> => {
    const response = await apiClient.get<BoundaryDispute[]>('/boundary/disputes', { params });
    return response.data;
  },

  // Get dispute details
  getDispute: async (disputeNumber: string): Promise<DisputeSearchResult> => {
    const response = await apiClient.get<DisputeSearchResult>(`/boundary/disputes/${disputeNumber}`);
    return response.data;
  },

  // Create dispute
  createDispute: async (dispute: Partial<BoundaryDispute>): Promise<BoundaryDispute> => {
    const response = await apiClient.post<BoundaryDispute>('/boundary/disputes', dispute);
    return response.data;
  },

  // GIS GeoJSON (for GIS Viewer, QGIS-compatible)
  fetchBoundariesGeoJSON: async (params?: { boundary_number?: string }): Promise<GeoJSONFeatureCollection> => {
    const response = await apiClient.get<GeoJSONFeatureCollection>('/gis/boundaries/geojson', { params });
    return response.data;
  },
  fetchPropertiesGeoJSON: async (params?: { property_number?: string; owner?: string }): Promise<GeoJSONFeatureCollection> => {
    const response = await apiClient.get<GeoJSONFeatureCollection>('/gis/properties/geojson', { params });
    return response.data;
  },
  fetchSurveyPlansGeoJSON: async (params?: { property_number?: string }): Promise<GeoJSONFeatureCollection> => {
    const response = await apiClient.get<GeoJSONFeatureCollection>('/gis/survey-plans/geojson', { params });
    return response.data;
  },

  // List documents
  listDocuments: async (params?: {
    related_boundary_id?: number;
    related_dispute_id?: number;
    document_type?: string;
    limit?: number;
    offset?: number;
  }): Promise<{ count: number; documents: any[] }> => {
    const response = await apiClient.get('/boundary/documents/list', { params });
    return response.data;
  },

  // Get document PDF URL
  getDocumentPdfUrl: (documentNumber: string): string => {
    return `/boundary/documents/pdf-by-document-number?document_number=${encodeURIComponent(documentNumber)}`;
  },
};

// Landing page (public, no auth)
export interface LandingHero {
  id: number;
  title: string;
  subtitle: string;
  banner_text: string | null;
  background_image_url: string | null;
  updated_at: string | null;
}
export interface LandingStat {
  id: number;
  label: string;
  value: string;
  sort_order: number;
  created_at: string | null;
}
export interface LandingServicesBlock {
  id: number;
  title: string;
  body_text: string | null;
  image_url: string | null;
  button_1_label: string | null;
  button_1_url: string | null;
  button_2_label: string | null;
  button_2_url: string | null;
  button_3_label: string | null;
  button_3_url: string | null;
  updated_at: string | null;
}
export interface LandingServiceCard {
  id: number;
  title: string;
  description: string | null;
  link_url: string | null;
  sort_order: number;
  created_at: string | null;
}
export interface LandingContact {
  id: number;
  phone: string | null;
  email: string | null;
  address: string | null;
  updated_at: string | null;
}
export interface LandingResponse {
  hero: LandingHero;
  stats: LandingStat[];
  services_block: LandingServicesBlock;
  service_cards: LandingServiceCard[];
  contact: LandingContact;
}

/** Public landing content (no auth). */
export async function fetchLanding(): Promise<LandingResponse> {
  const base = getApiBaseUrl();
  const url = base.endsWith('/') ? `${base}landing` : `${base}/landing`;
  const res = await fetch(url);
  if (!res.ok) {
    const text = await res.text();
    throw new Error(text || `Landing fetch failed: ${res.status}`);
  }
  return res.json();
}

/** Admin landing CRUD (requires auth). */
export const landingAdminApi = {
  get: () => apiClient.get<LandingResponse>('/landing/admin').then((r) => r.data),
  putHero: (data: Partial<Pick<LandingHero, 'title' | 'subtitle' | 'banner_text' | 'background_image_url'>>) =>
    apiClient.put<LandingHero>('/landing/hero', data).then((r) => r.data),
  getStats: () => apiClient.get<LandingStat[]>('/landing/stats').then((r) => r.data),
  postStat: (data: { label: string; value: string; sort_order?: number }) =>
    apiClient.post<LandingStat>('/landing/stats', data).then((r) => r.data),
  putStat: (id: number, data: Partial<{ label: string; value: string; sort_order: number }>) =>
    apiClient.put<LandingStat>(`/landing/stats/${id}`, data).then((r) => r.data),
  deleteStat: (id: number) => apiClient.delete(`/landing/stats/${id}`),
  putServicesBlock: (data: Partial<Omit<LandingServicesBlock, 'id' | 'updated_at'>>) =>
    apiClient.put<LandingServicesBlock>('/landing/services-block', data).then((r) => r.data),
  getServiceCards: () => apiClient.get<LandingServiceCard[]>('/landing/service-cards').then((r) => r.data),
  postServiceCard: (data: { title: string; description?: string; link_url?: string; sort_order?: number }) =>
    apiClient.post<LandingServiceCard>('/landing/service-cards', data).then((r) => r.data),
  putServiceCard: (id: number, data: Partial<{ title: string; description: string; link_url: string; sort_order: number }>) =>
    apiClient.put<LandingServiceCard>(`/landing/service-cards/${id}`, data).then((r) => r.data),
  deleteServiceCard: (id: number) => apiClient.delete(`/landing/service-cards/${id}`),
  putContact: (data: Partial<Pick<LandingContact, 'phone' | 'email' | 'address'>>) =>
    apiClient.put<LandingContact>('/landing/contact', data).then((r) => r.data),
};

