import { createSignal, createResource, createEffect, Accessor, Resource } from 'solid-js';

// API base URL - can be configured via environment
const API_BASE = import.meta.env.VITE_API_BASE_URL || '';

// Types
export interface CreditBalance {
  credits: number;
  tracecoin_balance: number;
  plan_code?: string;
  plan_name?: string;
  daily_action_limit?: number;
  remaining_daily_actions?: number;
}

export interface GenerateRequest {
  type: 'job_description' | 'interview_question' | 'resume_review';
  context: Record<string, unknown>;
}

export interface GenerateResponse {
  content: string;
  credits_used: number;
  remaining_credits: number;
  remaining_daily_actions?: number;
}

export interface PurchaseRequest {
  amount: number;
  payment_method: string;
}

export interface PurchaseResponse {
  success: boolean;
  credits_added: number;
  new_balance: number;
  transaction_id: string;
}

function authHeaders(): HeadersInit {
  const token = typeof window !== 'undefined'
    ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
    : '';
  return {
    'Content-Type': 'application/json',
    ...(token ? { Authorization: `Bearer ${token}` } : {}),
  };
}

function mapPurchaseAmountToAddonCode(amount: number): string {
  if (amount <= 50) return 'STARTER';
  if (amount <= 150) return 'GROWTH';
  if (amount <= 500) return 'POWER';
  return 'ENTERPRISE';
}

function stringifyContext(context: Record<string, unknown>): string {
  return Object.entries(context)
    .filter(([, value]) => value !== null && value !== undefined && String(value).trim() !== '')
    .map(([key, value]) => `${key}: ${String(value)}`)
    .join('\n');
}

export interface ApiError {
  code: string;
  message: string;
  details?: Record<string, unknown>;
}

// Credit costs for different operations
export const CREDIT_COSTS: Record<string, number> = {
  job_description: 1,
  interview_question: 1,
  resume_review: 2,
};

// Fetch credit balance from API
async function fetchCredits(): Promise<CreditBalance> {
  const response = await fetch(`${API_BASE}/api/ai/credits/balance`, {
    method: 'GET',
    headers: authHeaders(),
    credentials: 'include',
  });

  if (!response.ok) {
    const error: ApiError = await response.json().catch(() => ({
      code: 'FETCH_ERROR',
      message: `Failed to fetch credits: ${response.statusText}`,
    }));
    throw new Error(error.message);
  }

  const data = await response.json();
  return {
    credits: data.remaining_credits ?? 0,
    tracecoin_balance: 0,
    plan_code: data.plan_code,
    plan_name: data.plan_name,
    daily_action_limit: data.daily_limit,
    remaining_daily_actions: Math.max(0, (data.daily_limit ?? 0) - (data.daily_used ?? 0)),
  };
}

// Generate AI content
export async function generateContent(
  request: GenerateRequest
): Promise<GenerateResponse> {
  const context = stringifyContext(request.context);

  let path = '/api/ai/help/ask';
  let body: Record<string, unknown> = { message: context || request.type };

  if (request.type === 'job_description') {
    path = '/api/ai/company/jobs/generate-description';
    body = { context };
  } else if (request.type === 'resume_review') {
    path = '/api/ai/help/ask';
    body = { message: `Review and improve this resume content:
${context}` };
  } else if (request.type === 'interview_question') {
    path = '/api/ai/help/ask';
    body = { message: `Generate interview guidance or questions for:
${context}` };
  }

  const response = await fetch(`${API_BASE}${path}`, {
    method: 'POST',
    headers: authHeaders(),
    credentials: 'include',
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const error: ApiError = await response.json().catch(() => ({
      code: 'GENERATE_ERROR',
      message: `Failed to generate content: ${response.statusText}`,
    }));

    if (response.status === 402) {
      throw new Error('Insufficient credits. Please purchase more credits to continue.');
    }

    throw new Error(error.message);
  }

  const data = await response.json();
  return {
    content: data.generated_text || data.message || data.reply || '',
    credits_used: data.credits_charged || 0,
    remaining_credits: data.remaining_credits || 0,
    remaining_daily_actions: data.remaining_daily_actions || data.remaining_today,
  };
}

// Purchase credits
export async function purchaseCredits(
  request: PurchaseRequest
): Promise<PurchaseResponse> {
  const response = await fetch(`${API_BASE}/api/ai/credits/buy`, {
    method: 'POST',
    headers: authHeaders(),
    credentials: 'include',
    body: JSON.stringify({ addon_code: mapPurchaseAmountToAddonCode(request.amount) }),
  });

  if (!response.ok) {
    const error: ApiError = await response.json().catch(() => ({
      code: 'PURCHASE_ERROR',
      message: `Failed to purchase credits: ${response.statusText}`,
    }));
    throw new Error(error.message);
  }

  const data = await response.json();
  return {
    success: !!data.success,
    credits_added: request.amount,
    new_balance: data.addon_balance || 0,
    transaction_id: data.transaction_id || `addon:${mapPurchaseAmountToAddonCode(request.amount)}`,
  };
}

// Main hook for credit management
export interface UseAiCreditsReturn {
  // Credit data
  credits: Accessor<number>;
  tracecoinBalance: Accessor<number>;
  creditResource: Resource<CreditBalance>;
  
  // Loading states
  isLoading: Accessor<boolean>;
  isGenerating: Accessor<boolean>;
  isPurchasing: Accessor<boolean>;
  
  // Error states
  error: Accessor<string | null>;
  generationError: Accessor<string | null>;
  purchaseError: Accessor<string | null>;
  
  // Actions
  refetchCredits: () => void;
  generate: (request: GenerateRequest) => Promise<GenerateResponse | null>;
  purchase: (request: PurchaseRequest) => Promise<PurchaseResponse | null>;
  clearErrors: () => void;
  hasEnoughCredits: (cost?: number) => boolean;
}

export function useAiCredits(): UseAiCreditsReturn {
  // Resource for fetching credits
  const [creditResource, { refetch: refetchCredits }] = createResource<CreditBalance>(
    fetchCredits,
    {
      initialValue: { credits: 0, tracecoin_balance: 0 },
    }
  );

  // Loading states
  const [isGenerating, setIsGenerating] = createSignal(false);
  const [isPurchasing, setIsPurchasing] = createSignal(false);

  // Error states
  const [error, setError] = createSignal<string | null>(null);
  const [generationError, setGenerationError] = createSignal<string | null>(null);
  const [purchaseError, setPurchaseError] = createSignal<string | null>(null);

  // Derived signals for credit data
  const credits = () => creditResource()?.credits ?? 0;
  const tracecoinBalance = () => creditResource()?.tracecoin_balance ?? 0;
  const isLoading = () => creditResource.loading;

  // Clear all errors
  const clearErrors = () => {
    setError(null);
    setGenerationError(null);
    setPurchaseError(null);
  };

  // Check if user has enough credits
  const hasEnoughCredits = (cost: number = 1): boolean => credits() >= cost;

  // Generate AI content with error handling
  const generate = async (
    request: GenerateRequest
  ): Promise<GenerateResponse | null> => {
    setIsGenerating(true);
    setGenerationError(null);
    
    try {
      const response = await generateContent(request);
      // Refetch credits to get updated balance
      refetchCredits();
      return response;
    } catch (err) {
      const message = err instanceof Error ? err.message : 'Failed to generate content';
      setGenerationError(message);
      throw err;
    } finally {
      setIsGenerating(false);
    }
  };

  // Purchase credits with error handling
  const purchase = async (
    request: PurchaseRequest
  ): Promise<PurchaseResponse | null> => {
    setIsPurchasing(true);
    setPurchaseError(null);
    
    try {
      const response = await purchaseCredits(request);
      // Refetch credits to get updated balance
      refetchCredits();
      return response;
    } catch (err) {
      const message = err instanceof Error ? err.message : 'Failed to purchase credits';
      setPurchaseError(message);
      throw err;
    } finally {
      setIsPurchasing(false);
    }
  };

  // Auto-clear resource errors
  createEffect(() => {
    if (creditResource.error) {
      const err = creditResource.error as Error;
      setError(err.message || 'Failed to load credits');
    }
  });

  return {
    // Credit data
    credits,
    tracecoinBalance,
    creditResource,
    
    // Loading states
    isLoading,
    isGenerating,
    isPurchasing,
    
    // Error states
    error,
    generationError,
    purchaseError,
    
    // Actions
    refetchCredits,
    generate,
    purchase,
    clearErrors,
    hasEnoughCredits,
  };
}

export default useAiCredits;
