import axios, { type AxiosError, type AxiosInstance } from 'axios';
import type { ApiError } from '@/shared/types';

const API_URL = import.meta.env.VITE_API_URL || '/api';

class ApiClient {
  private client: AxiosInstance;
  private token: string | null = null;

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

    // Load token from localStorage (persistent) or sessionStorage (session-only)
    this.token = localStorage.getItem('auth_token') || sessionStorage.getItem('auth_token');

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

    // Response interceptor to handle errors
    this.client.interceptors.response.use(
      (response) => response,
      (error: AxiosError<ApiError>) => {
        // Don't redirect on 401 for auth endpoints (login, register)
        const isAuthEndpoint = error.config?.url?.startsWith('/auth/login') ||
                               error.config?.url?.startsWith('/auth/register');

        if (error.response?.status === 401 && !isAuthEndpoint) {
          this.clearToken();
          window.location.href = '/login';
        }
        return Promise.reject(error);
      }
    );
  }

  setToken(token: string, remember: boolean = true) {
    this.token = token;
    if (remember) {
      localStorage.setItem('auth_token', token);
      sessionStorage.removeItem('auth_token');
    } else {
      sessionStorage.setItem('auth_token', token);
      localStorage.removeItem('auth_token');
    }
  }

  clearToken() {
    this.token = null;
    localStorage.removeItem('auth_token');
    sessionStorage.removeItem('auth_token');
  }

  getToken() {
    return this.token;
  }

  // Auth endpoints
  async login(identifier: string, password: string) {
    const response = await this.client.post('/auth/login', { identifier, password });
    return response.data;
  }

  async register(username: string, email: string, password: string) {
    const response = await this.client.post('/auth/register', { username, email, password });
    return response.data;
  }

  async getProfile() {
    const response = await this.client.get('/auth/me');
    return response.data;
  }

  async updateProfile(data: { avatarUrl?: string }) {
    const response = await this.client.put('/auth/profile', data);
    return response.data;
  }

  async searchUsers(query: string) {
    const response = await this.client.get('/auth/users/search', { params: { q: query } });
    return response.data;
  }

  // Campaign endpoints
  async getCampaigns() {
    const response = await this.client.get('/campaigns');
    return response.data;
  }

  async getCampaign(id: string) {
    const response = await this.client.get(`/campaigns/${id}`);
    return response.data;
  }

  async createCampaign(data: { name: string; description?: string; imageUrl?: string }) {
    const response = await this.client.post('/campaigns', data);
    return response.data;
  }

  async updateCampaign(id: string, data: { name?: string; description?: string; imageUrl?: string }) {
    const response = await this.client.put(`/campaigns/${id}`, data);
    return response.data;
  }

  async deleteCampaign(id: string) {
    const response = await this.client.delete(`/campaigns/${id}`);
    return response.data;
  }

  async addCampaignMember(campaignId: string, userId: string) {
    const response = await this.client.post(`/campaigns/${campaignId}/members`, { userId });
    return response.data;
  }

  async removeCampaignMember(campaignId: string, userId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/members/${userId}`);
    return response.data;
  }

  // Character endpoints
  async getCharacters(campaignId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters`);
    return response.data;
  }

  async getCharacter(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}`);
    return response.data;
  }

  async createCharacter(campaignId: string, data: {
    name: string;
    type?: 'PC' | 'NPC';
    level?: number;
    avatarUrl?: string;
    hpCurrent: number;
    hpMax: number;
    hpTemp?: number;
    ancestryId?: string;
    heritageId?: string;
    classId?: string;
    backgroundId?: string;
    experiencePoints?: number;
    pathbuilderData?: unknown;
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters`, data);
    return response.data;
  }

  async importCharacterFromPathbuilder(campaignId: string, pathbuilderJson: unknown) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/import`, {
      pathbuilderJson,
    });
    return response.data;
  }

  async updateCharacter(campaignId: string, characterId: string, data: Partial<{
    name: string;
    type: 'PC' | 'NPC';
    level: number;
    avatarUrl: string;
    hpCurrent: number;
    hpMax: number;
    hpTemp: number;
    ancestryId: string;
    heritageId: string;
    classId: string;
    backgroundId: string;
  }>) {
    const response = await this.client.put(`/campaigns/${campaignId}/characters/${characterId}`, data);
    return response.data;
  }

  async deleteCharacter(campaignId: string, characterId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}`);
    return response.data;
  }

  async updateCharacterHp(campaignId: string, characterId: string, hpCurrent: number, hpTemp?: number) {
    const response = await this.client.patch(`/campaigns/${campaignId}/characters/${characterId}/hp`, { hpCurrent, hpTemp });
    return response.data;
  }

  async updateCharacterCredits(campaignId: string, characterId: string, credits: number) {
    const response = await this.client.patch(`/campaigns/${campaignId}/characters/${characterId}/credits`, { credits });
    return response.data;
  }

  // Conditions
  async addCharacterCondition(campaignId: string, characterId: string, data: {
    name: string;
    nameGerman?: string;
    value?: number;
    duration?: string;
    source?: string;
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/conditions`, data);
    return response.data;
  }

  async removeCharacterCondition(campaignId: string, characterId: string, conditionId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}/conditions/${conditionId}`);
    return response.data;
  }

  // Character Items
  async addCharacterItem(campaignId: string, characterId: string, data: {
    equipmentId?: string;
    name: string;
    nameGerman?: string;
    quantity?: number;
    bulk?: number;
    equipped?: boolean;
    invested?: boolean;
    notes?: string;
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/items`, data);
    return response.data;
  }

  async updateCharacterItem(campaignId: string, characterId: string, itemId: string, data: {
    // Player-editable fields
    quantity?: number;
    equipped?: boolean;
    invested?: boolean;
    notes?: string;
    alias?: string;
    // GM-only fields
    customName?: string;
    customDamage?: string;
    customDamageType?: string;
    customTraits?: string[];
    customRange?: string;
    customHands?: string;
  }) {
    const response = await this.client.patch(`/campaigns/${campaignId}/characters/${characterId}/items/${itemId}`, data);
    return response.data;
  }

  async removeCharacterItem(campaignId: string, characterId: string, itemId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}/items/${itemId}`);
    return response.data;
  }

  // Character Feats
  async addCharacterFeat(campaignId: string, characterId: string, data: {
    featId?: string;
    name: string;
    nameGerman?: string;
    level: number;
    source: 'CLASS' | 'ANCESTRY' | 'GENERAL' | 'SKILL' | 'BONUS' | 'ARCHETYPE';
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/feats`, data);
    return response.data;
  }

  async removeCharacterFeat(campaignId: string, characterId: string, featId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}/feats/${featId}`);
    return response.data;
  }

  // Equipment Database (Browse/Search)
  async searchEquipment(params: {
    query?: string;
    category?: string;
    subcategory?: string;
    minLevel?: number;
    maxLevel?: number;
    traits?: string[];
    page?: number;
    limit?: number;
  }) {
    const queryParams = new URLSearchParams();
    if (params.query) queryParams.set('query', params.query);
    if (params.category) queryParams.set('category', params.category);
    if (params.subcategory) queryParams.set('subcategory', params.subcategory);
    if (params.minLevel !== undefined) queryParams.set('minLevel', params.minLevel.toString());
    if (params.maxLevel !== undefined) queryParams.set('maxLevel', params.maxLevel.toString());
    if (params.traits?.length) queryParams.set('traits', params.traits.join(','));
    if (params.page) queryParams.set('page', params.page.toString());
    if (params.limit) queryParams.set('limit', params.limit.toString());

    const response = await this.client.get(`/equipment?${queryParams.toString()}`);
    return response.data;
  }

  async getEquipmentCategories() {
    const response = await this.client.get('/equipment/categories');
    return response.data;
  }

  async getEquipmentSubcategories(category: string) {
    const response = await this.client.get(`/equipment/categories/${encodeURIComponent(category)}/subcategories`);
    return response.data;
  }

  async getEquipmentById(id: string) {
    const response = await this.client.get(`/equipment/${id}`);
    return response.data;
  }

  async getEquipmentByName(name: string) {
    const response = await this.client.get(`/equipment/by-name/${encodeURIComponent(name)}`);
    return response.data;
  }

  // Feats Database (Browse/Search)
  async searchFeats(params: {
    query?: string;
    featType?: string;
    className?: string;
    ancestryName?: string;
    skillName?: string;
    minLevel?: number;
    maxLevel?: number;
    rarity?: string;
    traits?: string[];
    page?: number;
    limit?: number;
  }) {
    const queryParams = new URLSearchParams();
    if (params.query) queryParams.set('query', params.query);
    if (params.featType) queryParams.set('featType', params.featType);
    if (params.className) queryParams.set('className', params.className);
    if (params.ancestryName) queryParams.set('ancestryName', params.ancestryName);
    if (params.skillName) queryParams.set('skillName', params.skillName);
    if (params.minLevel !== undefined) queryParams.set('minLevel', params.minLevel.toString());
    if (params.maxLevel !== undefined) queryParams.set('maxLevel', params.maxLevel.toString());
    if (params.rarity) queryParams.set('rarity', params.rarity);
    if (params.traits?.length) queryParams.set('traits', params.traits.join(','));
    if (params.page) queryParams.set('page', params.page.toString());
    if (params.limit) queryParams.set('limit', params.limit.toString());

    const response = await this.client.get(`/feats?${queryParams.toString()}`);
    return response.data;
  }

  async getFeatTypes() {
    const response = await this.client.get('/feats/types');
    return response.data;
  }

  async getFeatClasses() {
    const response = await this.client.get('/feats/classes');
    return response.data;
  }

  async getFeatAncestries() {
    const response = await this.client.get('/feats/ancestries');
    return response.data;
  }

  async getFeatTraits() {
    const response = await this.client.get('/feats/traits');
    return response.data;
  }

  async getFeatById(id: string) {
    const response = await this.client.get(`/feats/${id}`);
    return response.data;
  }

  async getFeatByName(name: string) {
    const response = await this.client.get(`/feats/by-name/${encodeURIComponent(name)}`);
    return response.data;
  }

  // ==========================================
  // REST SYSTEM
  // ==========================================

  async getRestPreview(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}/rest/preview`);
    return response.data;
  }

  async performRest(campaignId: string, characterId: string) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/rest`);
    return response.data;
  }

  // ==========================================
  // ALCHEMY SYSTEM
  // ==========================================

  async getAlchemy(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}/alchemy`);
    return response.data;
  }

  async initializeAlchemy(campaignId: string, characterId: string, data: {
    researchField?: 'BOMBER' | 'CHIRURGEON' | 'MUTAGENIST' | 'TOXICOLOGIST';
    versatileVialsMax: number;
    advancedAlchemyMax: number;
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/initialize`, data);
    return response.data;
  }

  async updateVials(campaignId: string, characterId: string, current: number) {
    const response = await this.client.patch(`/campaigns/${campaignId}/characters/${characterId}/alchemy/vials`, { current });
    return response.data;
  }

  async refillVials(campaignId: string, characterId: string) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/vials/refill`);
    return response.data;
  }

  async getFormulas(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}/alchemy/formulas`);
    return response.data;
  }

  async getAvailableFormulas(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}/alchemy/formulas/available`);
    return response.data;
  }

  async addFormula(campaignId: string, characterId: string, data: {
    equipmentId: string;
    learnedAt?: number;
    formulaSource?: string;
  }) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/formulas`, data);
    return response.data;
  }

  async removeFormula(campaignId: string, characterId: string, formulaId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}/alchemy/formulas/${formulaId}`);
    return response.data;
  }

  async refreshFormulaTranslations(campaignId: string, characterId: string) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/formulas/refresh-translations`);
    return response.data;
  }

  async getPreparedItems(campaignId: string, characterId: string) {
    const response = await this.client.get(`/campaigns/${campaignId}/characters/${characterId}/alchemy/prepared`);
    return response.data;
  }

  async dailyPreparation(campaignId: string, characterId: string, items: Array<{ equipmentId: string; quantity: number }>) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/prepare`, { items });
    return response.data;
  }

  async quickAlchemy(campaignId: string, characterId: string, equipmentId: string) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/quick`, { equipmentId });
    return response.data;
  }

  async craftAlchemy(campaignId: string, characterId: string, equipmentId: string, quantity: number) {
    const response = await this.client.post(`/campaigns/${campaignId}/characters/${characterId}/alchemy/craft`, { equipmentId, quantity });
    return response.data;
  }

  async consumePreparedItem(campaignId: string, characterId: string, itemId: string) {
    const response = await this.client.patch(`/campaigns/${campaignId}/characters/${characterId}/alchemy/prepared/${itemId}/consume`);
    return response.data;
  }

  async deletePreparedItem(campaignId: string, characterId: string, itemId: string) {
    const response = await this.client.delete(`/campaigns/${campaignId}/characters/${characterId}/alchemy/prepared/${itemId}`);
    return response.data;
  }
}

export const api = new ApiClient();
