import { GlobalFunctions, TransferAreaProperties } from '@/GlobalFunctions';
import { apiService } from './api';

/**
 * Tamanhos de imagem disponíveis
 */
export type ImageSize = '1024x1024' | '1024x1792' | '1792x1024';

/**
 * Interface para a resposta da API de geração de imagens
 */
export interface ImageGenerationResponse {
  success: boolean;
  image_url?: string; // URL da imagem gerada (opcional quando há erro)
  image_generation_id?: string; // ID da geração (opcional quando há erro)
  message: string; // Descrição original ou mensagem de erro
  code?: string; // Código de erro (ex: "server_error", "invalid_request")
}

/**
 * Interface para uma imagem armazenada no banco de dados
 */
export interface ImageRecord {
  id: string;
  user_email: string;
  estabelecimento_id: number;
  description: string;
  model: string;
  image_url: string;
  size: ImageSize;
  cost_usd: string;
  total_tokens: number;
  input_tokens: number;
  output_tokens: number;
  created_at: string;
}

/**
 * Interface para resposta paginada de imagens
 */
export interface GetImagesResponse {
  images: ImageRecord[];
  total: number;
  page: number;
  per_page: number;
  total_pages: number;
}

/**
 * Interface para os dados necessários para geração de imagem
 */
export interface ImageGenerationRequest {
  description: string;
  size: ImageSize;
  userEmail?: string;
  estabelecimentoId?: number;
}

/**
 * Informações sobre cada tamanho de imagem disponível
 */
export const IMAGE_SIZE_OPTIONS = {
  '1024x1024': {
    label: 'Quadrado',
    dimensions: '1024x1024',
    aspectRatio: '1:1',
    description: 'Ideal para avatares, ícones e posts em redes sociais',
  },
  '1024x1792': {
    label: 'Retrato',
    dimensions: '1024x1792',
    aspectRatio: '9:16',
    description: 'Perfeito para stories, wallpapers verticais e reels',
  },
  '1792x1024': {
    label: 'Paisagem',
    dimensions: '1792x1024',
    aspectRatio: '16:9',
    description: 'Ótimo para banners, capas e thumbnails de vídeos',
  },
} as const;

/**
 * Serviço de geração de imagens com IA
 */
class ImageGenerationService {
  private readonly IMAGE_GENERATION_ENDPOINT = '/webhook/codex/image_generator';
  private readonly GET_IMAGES_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_images';
  private readonly DELETE_IMAGE_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_images';

  /**
   * Gera uma imagem a partir de uma descrição em texto
   *
   * @param request - Dados da requisição (descrição, tamanho, email, estabelecimento)
   * @returns Promise com a resposta da API
   */
  async generateImage(request: ImageGenerationRequest): Promise<ImageGenerationResponse> {
    const { description, size, userEmail, estabelecimentoId } = request;

    // Usa valores do .env se não forem fornecidos
    const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);//userEmail || import.meta.env.VITE_USER_EMAIL || '';
    const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);//estabelecimentoId || parseInt(import.meta.env.VITE_ESTABELECIMENTO_ID) || 1;

    // Valida a descrição
    if (!description || description.trim().length === 0) {
      throw {
        success: false,
        message: 'A descrição não pode estar vazia',
      };
    }

    // Valida o tamanho
    if (!this.isValidSize(size)) {
      throw {
        success: false,
        message: `Tamanho inválido. Opções disponíveis: ${Object.keys(IMAGE_SIZE_OPTIONS).join(', ')}`,
      };
    }

    // Log para debug (remover em produção se necessário)
    console.log('Gerando imagem:', {
      descriptionLength: description.length,
      size,
      userEmail: email,
      estabelecimentoId: estabId,
    });

    try {
      // Faz a requisição usando o serviço de API
      // Nota: O campo no body é "estabelecito_id" (com typo na API)
      const response = await apiService.post<ImageGenerationResponse>(
        this.IMAGE_GENERATION_ENDPOINT,
        {
          estabelecimento_id: estabId, // Mantém o typo da API original
          user_email: email,
          description: description,
          size: size,
        }
      );

      // Verifica se a resposta indica erro
      if (!response.data.success) {
        throw {
          success: false,
          message: response.data.message || 'Erro ao gerar imagem',
          code: response.data.code,
        };
      }

      return response.data;
    } catch (error: any) {
      // Trata erros específicos da API
      console.error('Erro na geração de imagem:', error);

      // Se o erro já tem a estrutura esperada (veio da validação acima), repassa
      if (error.success === false && error.message) {
        throw error;
      }

      // Se o erro veio da requisição HTTP, tenta extrair a resposta da API
      if (error.response?.data) {
        const apiError = error.response.data;
        throw {
          success: false,
          message: apiError.message || 'Erro ao gerar imagem',
          code: apiError.code,
        };
      }

      // Erro genérico
      throw {
        success: false,
        message: error.message || 'Erro ao gerar imagem. Tente novamente.',
        status: error.status,
      };
    }
  }

  /**
   * Valida se o tamanho selecionado é suportado
   *
   * @param size - Tamanho a ser validado
   * @returns true se o tamanho é válido
   */
  isValidSize(size: string): size is ImageSize {
    return Object.keys(IMAGE_SIZE_OPTIONS).includes(size);
  }

  /**
   * Obtém informações sobre um tamanho específico
   *
   * @param size - Tamanho da imagem
   * @returns Informações do tamanho
   */
  getSizeInfo(size: ImageSize) {
    return IMAGE_SIZE_OPTIONS[size];
  }

  /**
   * Lista todos os tamanhos disponíveis
   *
   * @returns Array com todas as opções de tamanho
   */
  getAllSizes() {
    return Object.entries(IMAGE_SIZE_OPTIONS).map(([key, info]) => ({
      value: key as ImageSize,
      ...info,
    }));
  }

  /**
   * Valida a descrição para geração de imagem
   *
   * @param description - Descrição a ser validada
   * @param minLength - Comprimento mínimo (padrão: 3 caracteres)
   * @param maxLength - Comprimento máximo (padrão: 1000 caracteres)
   * @returns Objeto com resultado da validação
   */
  validateDescription(
    description: string,
    minLength: number = 3,
    maxLength: number = 1000
  ): { valid: boolean; error?: string } {
    if (!description || description.trim().length === 0) {
      return {
        valid: false,
        error: 'A descrição não pode estar vazia',
      };
    }

    if (description.trim().length < minLength) {
      return {
        valid: false,
        error: `A descrição deve ter pelo menos ${minLength} caracteres`,
      };
    }

    if (description.length > maxLength) {
      return {
        valid: false,
        error: `A descrição é muito longa. Máximo: ${maxLength} caracteres`,
      };
    }

    return { valid: true };
  }

  /**
   * Faz download de uma imagem gerada
   *
   * @param imageUrl - URL da imagem
   * @param filename - Nome do arquivo (opcional)
   */
  async downloadImage(imageUrl: string, filename?: string): Promise<void> {
    try {
      const response = await fetch(imageUrl);
      const blob = await response.blob();
      const url = URL.createObjectURL(blob);

      const a = document.createElement('a');
      a.href = url;
      a.download = filename || `imagem_${Date.now()}.png`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);

      URL.revokeObjectURL(url);
    } catch (error) {
      console.error('Erro ao baixar imagem:', error);
      throw new Error('Não foi possível baixar a imagem');
    }
  }

  /**
   * Lista imagens do banco de dados com paginação
   *
   * @param userEmail - Email do usuário
   * @param page - Número da página (padrão: 1)
   * @param perPage - Quantidade de itens por página (padrão: 10)
   * @returns Promise com a resposta paginada
   */
  async getImages(
    userEmail?: string,
    page: number = 1,
    perPage: number = 10
  ): Promise<ImageRecord[]> {
    // Usa valores do GlobalFunctions se não forem fornecidos
    const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);

    if (!email) {
      throw {
        success: false,
        message: 'Email do usuário não fornecido',
      };
    }

    console.log('Buscando imagens:', {
      userEmail: email,
      page,
      perPage,
    });

    try {
      // Faz a requisição GET com parâmetros na URL e query
      const response = await apiService.get<ImageRecord[]>(
        `${this.GET_IMAGES_ENDPOINT}/${email}`,
        {
          params: {
            page: page.toString(),
            per_page: perPage.toString(),
          },
        }
      );

      console.log('Resposta completa da API:', response);
      console.log('response.data:', response.data);
      console.log('É array?:', Array.isArray(response.data));

      // A API retorna diretamente o array de imagens
      // Garante que sempre retorna um array
      if (Array.isArray(response.data)) {
        return response.data;
      } else if (response.data && typeof response.data === 'object') {
        // Se a resposta for um objeto com uma propriedade 'images' ou similar
        console.warn('API retornou objeto em vez de array:', response.data);

        // Tenta encontrar o array dentro do objeto
        if (Array.isArray((response.data as any).images)) {
          return (response.data as any).images;
        } else if (Array.isArray((response.data as any).data)) {
          return (response.data as any).data;
        }
      }

      // Se não conseguir extrair array, retorna vazio
      console.warn('Não foi possível extrair array de imagens da resposta');
      return [];
    } catch (error: any) {
      console.error('Erro ao buscar imagens:', error);

      throw {
        success: false,
        message: error.message || 'Erro ao buscar imagens',
        status: error.status,
      };
    }
  }

  /**
   * Deleta uma imagem do banco de dados
   *
   * @param imageId - ID da imagem a ser deletada
   * @param userEmail - Email do usuário (opcional)
   * @returns Promise com sucesso ou erro
   */
  async deleteImage(imageId: string, userEmail?: string): Promise<{ success: boolean; message?: string }> {
    // Usa valores do GlobalFunctions se não forem fornecidos
    const email = userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);

    if (!email) {
      throw {
        success: false,
        message: 'Email do usuário não fornecido',
      };
    }

    if (!imageId) {
      throw {
        success: false,
        message: 'ID da imagem não fornecido',
      };
    }

    console.log('Deletando imagem:', {
      imageId,
      userEmail: email,
    });

    try {
      // Faz a requisição DELETE com parâmetros na URL
      const response = await apiService.delete<{ success: boolean; message?: string } | Array<{ success: boolean; message?: string }>>(
        `${this.DELETE_IMAGE_ENDPOINT}/${email}/${imageId}`
      );

      console.log('Resposta completa do DELETE:', response);
      console.log('response.data:', response.data);

      // A API pode retornar um array com um objeto: [{"success":true}]
      // ou diretamente um objeto: {"success":true}
      let result: { success: boolean; message?: string };

      if (Array.isArray(response.data)) {
        // Se for array, pega o primeiro elemento
        result = response.data[0];
        console.log('API retornou array, usando primeiro elemento:', result);
      } else {
        // Se for objeto direto
        result = response.data;
        console.log('API retornou objeto direto:', result);
      }

      // Garante que tem a estrutura mínima
      return {
        success: result.success ?? true,
        message: result.message || 'Imagem deletada com sucesso',
      };
    } catch (error: any) {
      console.error('Erro ao deletar imagem:', error);

      throw {
        success: false,
        message: error.message || 'Erro ao deletar imagem',
        status: error.status,
      };
    }
  }
}

// Exporta instância única (Singleton)
export const imageGenerationService = new ImageGenerationService();
