import type { PostgrestError } from '@supabase/supabase-js';
import { toast } from 'sonner';
import { logger } from './logger';

/**
 * Hata türleri enum yapısı
 */
export enum ErrorType {
  NotFound = 'NOT_FOUND',
  Unauthorized = 'UNAUTHORIZED',
  Forbidden = 'FORBIDDEN',
  ValidationError = 'VALIDATION_ERROR',
  ServerError = 'SERVER_ERROR',
  NetworkError = 'NETWORK_ERROR',
  UnknownError = 'UNKNOWN_ERROR',
  RateLimit = 'RATE_LIMIT',
}

/**
 * Uygulama genelinde kullanılacak özel hata sınıfı
 */
export class APIError extends Error {
  public status?: number;
  public code?: string;
  public type: ErrorType;
  public details?: any;

  constructor(message: string, options: { status?: number; code?: string; type?: ErrorType; details?: any } = {}) {
    super(message);
    this.name = 'APIError';
    this.status = options.status;
    this.code = options.code;
    this.type = options.type || ErrorType.UnknownError;
    this.details = options.details;
  }
}

/**
 * Kullanıcı dostu Türkçe hata mesajları
 */
const ERROR_MESSAGES: Record<ErrorType, string> = {
  [ErrorType.NotFound]: 'Aradığınız kaynak bulunamadı.',
  [ErrorType.Unauthorized]: 'Bu işlem için giriş yapmanız gerekiyor.',
  [ErrorType.Forbidden]: 'Bu işlem için yetkiniz bulunmuyor.',
  [ErrorType.ValidationError]: 'Lütfen girdiğiniz bilgileri kontrol edin.',
  [ErrorType.ServerError]: 'Sunucu tarafında bir hata oluştu. Lütfen daha sonra tekrar deneyin.',
  [ErrorType.NetworkError]: 'İnternet bağlantınızı kontrol edin.',
  [ErrorType.UnknownError]: 'Beklenmedik bir hata oluştu.',
  [ErrorType.RateLimit]: 'Çok fazla istekte bulundunuz. Lütfen biraz bekleyin.',
};

/**
 * Hata kurtarma önerileri
 */
const ERROR_RECOVERY_SUGGESTIONS: Record<ErrorType, string> = {
  [ErrorType.NotFound]: 'Lütfen URL adresini kontrol edin veya ana sayfaya dönün.',
  [ErrorType.Unauthorized]: 'Lütfen giriş yapın veya kayıt olun.',
  [ErrorType.Forbidden]: 'Bu alanı görüntülemek için yönetici ile iletişime geçin.',
  [ErrorType.ValidationError]: 'Formdaki hataları düzelterek tekrar deneyin.',
  [ErrorType.ServerError]: 'Ekibimiz durumdan haberdar edildi. Lütfen sayfayı yenilemeyi deneyin.',
  [ErrorType.NetworkError]: 'Wi-Fi veya mobil veri bağlantınızı kontrol edip tekrar deneyin.',
  [ErrorType.UnknownError]: 'Sayfayı yenilemek sorunu çözebilir.',
  [ErrorType.RateLimit]: 'Lütfen birkaç dakika bekledikten sonra tekrar deneyin.',
};

/**
 * Supabase hatalarını APIError nesnesine dönüştürür
 */
export const handleSupabaseError = (error: PostgrestError | Error): APIError => {
  if ('code' in error) {
    // Supabase PostgrestError handling
    const code = error.code;
    const message = error.message;

    // Yaygın Supabase hata kodları eşleştirmesi
    if (code === 'PGRST116') {
      return new APIError(ERROR_MESSAGES[ErrorType.NotFound], { status: 404, code, type: ErrorType.NotFound });
    }
    if (code === '42501') {
      return new APIError(ERROR_MESSAGES[ErrorType.Forbidden], { status: 403, code, type: ErrorType.Forbidden });
    }
    if (code === '23505') {
      return new APIError('Bu kayıt zaten mevcut.', { status: 409, code, type: ErrorType.ValidationError });
    }

    return new APIError(message || ERROR_MESSAGES[ErrorType.ServerError], {
      code,
      type: ErrorType.ServerError,
      details: error,
    });
  }

  return new APIError(error.message || ERROR_MESSAGES[ErrorType.UnknownError], {
    type: ErrorType.UnknownError,
    details: error,
  });
};

/**
 * Network (Axios, Fetch vb.) hatalarını APIError nesnesine dönüştürür
 */
export const handleNetworkError = (error: any): APIError => {
  if (error.response) {
    // Sunucu yanıt verdi ama durum kodu 2xx dışında
    const status = error.response.status;
    let type = ErrorType.ServerError;

    if (status === 401) type = ErrorType.Unauthorized;
    if (status === 403) type = ErrorType.Forbidden;
    if (status === 404) type = ErrorType.NotFound;
    if (status === 422) type = ErrorType.ValidationError;
    if (status === 429) type = ErrorType.RateLimit;

    return new APIError(ERROR_MESSAGES[type], {
      status,
      type,
      details: error.response.data,
    });
  } 
  
  if (error.request) {
    // İstek yapıldı ama yanıt alınamadı
    return new APIError(ERROR_MESSAGES[ErrorType.NetworkError], {
      type: ErrorType.NetworkError,
      details: error.request,
    });
  }

  return new APIError(error.message || ERROR_MESSAGES[ErrorType.UnknownError], {
    type: ErrorType.UnknownError,
    details: error,
  });
};

/**
 * Herhangi bir hatadan kullanıcı dostu mesaj döndürür
 */
export const getErrorMessage = (error: any): string => {
  if (error instanceof APIError) {
    return error.message;
  }
  if (typeof error === 'string') {
    return error;
  }
  return ERROR_MESSAGES[ErrorType.UnknownError];
};

/**
 * Hatayı konsola ve (varsa) backend log servisine kaydeder
 */
export const logError = (error: any, context?: string) => {
  const message = getErrorMessage(error);
  const details = error instanceof APIError ? error.details : error;
  
  logger.error(`${context ? `[${context}] ` : ''}${message}`, error, {
    extra: {
      type: error instanceof APIError ? error.type : 'Unknown',
      code: error instanceof APIError ? error.code : undefined,
      status: error instanceof APIError ? error.status : undefined,
      details,
    },
  });
};

/**
 * Hatayı kullanıcıya toast bildirimi olarak gösterir
 */
export const showErrorToast = (error: any, title: string = 'Hata Oluştu') => {
  const apiError = error instanceof APIError ? error : 
                   (error.code ? handleSupabaseError(error) : handleNetworkError(error));
  
  const message = apiError.message;
  const suggestion = ERROR_RECOVERY_SUGGESTIONS[apiError.type];

  toast.error(title, {
    description: `${message}${suggestion ? `\n\n${suggestion}` : ''}`,
    duration: 5000,
  });

  // Otomatik loglama
  logError(apiError, 'UI Toast');
};

/**
 * Entegrasyon Örneği:
 * 
 * try {
 *   const { data, error } = await supabase.from('test').select();
 *   if (error) throw handleSupabaseError(error);
 * } catch (err) {
 *   showErrorToast(err);
 * }
 */
