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

export interface ChatResponse {
  success: boolean;
  response: string;
  chat_id: string;
}

export interface ChatMessageRequest {
  chatId: string;
  message: string;
  modelId: string;
  personalidade?: string;
  anexos?: File[];
  userEmail?: string;
  estabelecimentoId?: number;
}

export interface StoredChat {
  id: string;
  title: string;
  createdAt: Date;
  updatedAt: Date;
  model: string;
  systemPrompt: string;
  messages: Array<{
    id: string;
    role: 'user' | 'assistant';
    content: string;
    model?: string;
    timestamp: Date;
    attachments?: Array<{ name: string; type: string; size: number }>;
  }>;
}

export interface StoredFolder {
  id: string;
  name: string;
  createdAt: Date;
  chatIds: string[];
}

export interface FolderRecord {
  id: string;
  name: string;
  created_at: string;
  updated_at: string;
}

export interface ChatRecord {
  id: string;
  title: string;
  model_id: number;
  folder_id: string | null;
  created_at: string;
  updated_at: string;
  personalidade: string;
  estabelecimento_id: number;
}

export interface GetChatsAndFoldersResponse {
  chats: ChatRecord[];
  folders: FolderRecord[];
}

export interface MessageRecord {
  id: string;
  chat_id: string;
  role: 'user' | 'assistant';
  content: string;
  model_id: number;
  model_name?: string;
  has_attachments: number;
  input_tokens: number;
  output_tokens: number;
  total_tokens: number;
  cost_usd: string;
  created_at: string;
}

type ApiErrorShape = { message?: string; status?: number };
type ApiArrayResult = Array<{ success: boolean; [key: string]: unknown }>;

class ChatService {
  private readonly CHAT_ENDPOINT = '/webhook/codex/message';
  private readonly STORAGE_KEY_CHATS = 'hgtx_chats';
  private readonly STORAGE_KEY_FOLDERS = 'hgtx_folders';
  private readonly POST_FOLDER_ENDPOINT = '/webhook/codex/post_folders';
  private readonly GET_CHATS_FOLDERS_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_chat_folders';
  private readonly PUT_CHAT_IN_FOLDER_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/insert_chat_in_folder';
  private readonly DELETE_FOLDER_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_chat_folder';
  private readonly DELETE_CHAT_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/delete_chat_messages';
  private readonly GET_CHAT_MESSAGES_ENDPOINT = '/webhook/fd073ec0-81ab-4681-8acd-b0da71f6ad30/codex/get_chat_messages';

  private readonly ALLOWED_FILE_TYPES = {
    'application/pdf': { ext: '.pdf', label: 'PDF' },
    'image/png': { ext: '.png', label: 'PNG' },
    'image/jpeg': { ext: '.jpg, .jpeg', label: 'JPEG' },
    'image/webp': { ext: '.webp', label: 'WebP' },
  };

  private readonly MAX_ATTACHMENTS = 5;

  private resolveEmail(userEmail?: string): string {
    return userEmail || GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
  }

  private toApiError(error: unknown, fallback: string): never {
    const e = error as ApiErrorShape;
    throw { success: false, message: e?.message || fallback, status: e?.status };
  }

  private firstResult(data: unknown): { success: boolean } {
    if (Array.isArray(data) && data.length > 0) return data[0] as { success: boolean };
    return data as { success: boolean };
  }

  private extractArray<T>(data: unknown, keys: string[]): T[] {
    if (Array.isArray(data)) return data as T[];
    if (data && typeof data === 'object') {
      for (const key of keys) {
        const candidate = (data as Record<string, unknown>)[key];
        if (Array.isArray(candidate)) return candidate as T[];
      }
    }
    return [];
  }

  generateChatId(): string {
    const ts = Date.now().toString(36);
    const r1 = Math.random().toString(36).substring(2, 15);
    const r2 = Math.random().toString(36).substring(2, 15);
    return `chat_${ts}_${r1}${r2}`;
  }

  generateChatTitle(message: string, maxLength = 50): string {
    if (!message?.trim()) return 'Nova Conversa';
    const trimmed = message.trim();
    return trimmed.length <= maxLength ? trimmed : `${trimmed.substring(0, maxLength)}...`;
  }

  validateAttachments(files: File[]): { valid: boolean; error?: string } {
    if (files.length > this.MAX_ATTACHMENTS) {
      return { valid: false, error: `Máximo de ${this.MAX_ATTACHMENTS} anexos permitidos. Você selecionou ${files.length}.` };
    }
    for (const file of files) {
      if (!this.ALLOWED_FILE_TYPES[file.type as keyof typeof this.ALLOWED_FILE_TYPES]) {
        const ext = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));
        const extValid = Object.values(this.ALLOWED_FILE_TYPES).some((t) => t.ext.includes(ext));
        if (!extValid) {
          const allowed = Object.values(this.ALLOWED_FILE_TYPES).map((t) => t.label).join(', ');
          return { valid: false, error: `Arquivo "${file.name}" não é permitido. Formatos aceitos: ${allowed}` };
        }
      }
    }
    return { valid: true };
  }

  getAllowedFileTypes() {
    return Object.entries(this.ALLOWED_FILE_TYPES).map(([mimeType, info]) => ({ mimeType, ...info }));
  }

  getAllowedFileTypesLabel(): string {
    return Object.values(this.ALLOWED_FILE_TYPES).map((t) => t.label).join(', ');
  }

  getAllowedFileExtensions(): string {
    return Object.values(this.ALLOWED_FILE_TYPES).map((t) => t.ext).join(',');
  }

  getMaxAttachments(): number {
    return this.MAX_ATTACHMENTS;
  }

  saveChat(chat: StoredChat): void {
    try {
      const chats = this.getAllChats();
      const idx = chats.findIndex((c) => c.id === chat.id);
      if (idx >= 0) {
        chats[idx] = { ...chat, updatedAt: new Date() };
      } else {
        chats.push(chat);
      }
      localStorage.setItem(this.STORAGE_KEY_CHATS, JSON.stringify(chats));
    } catch {
      throw new Error('Não foi possível salvar o chat');
    }
  }

  getChat(chatId: string): StoredChat | undefined {
    return this.getAllChats().find((c) => c.id === chatId);
  }

  getAllChats(): StoredChat[] {
    try {
      const raw = localStorage.getItem(this.STORAGE_KEY_CHATS);
      if (!raw) return [];
      return (JSON.parse(raw) as StoredChat[]).map((chat) => ({
        ...chat,
        createdAt: new Date(chat.createdAt),
        updatedAt: new Date(chat.updatedAt),
        messages: chat.messages.map((msg) => ({ ...msg, timestamp: new Date(msg.timestamp) })),
      }));
    } catch {
      return [];
    }
  }

  deleteChatLocal(chatId: string): void {
    try {
      const filtered = this.getAllChats().filter((c) => c.id !== chatId);
      localStorage.setItem(this.STORAGE_KEY_CHATS, JSON.stringify(filtered));
    } catch {
      throw new Error('Não foi possível deletar o chat');
    }
  }

  saveFolder(folder: StoredFolder): void {
    try {
      const folders = this.getAllFolders();
      const idx = folders.findIndex((f) => f.id === folder.id);
      if (idx >= 0) {
        folders[idx] = folder;
      } else {
        folders.push(folder);
      }
      localStorage.setItem(this.STORAGE_KEY_FOLDERS, JSON.stringify(folders));
    } catch {
      throw new Error('Não foi possível salvar a pasta');
    }
  }

  getAllFolders(): StoredFolder[] {
    try {
      const raw = localStorage.getItem(this.STORAGE_KEY_FOLDERS);
      if (!raw) return [];
      return (JSON.parse(raw) as StoredFolder[]).map((f) => ({ ...f, createdAt: new Date(f.createdAt) }));
    } catch {
      return [];
    }
  }

  deleteFolderLocal(folderId: string): void {
    try {
      const filtered = this.getAllFolders().filter((f) => f.id !== folderId);
      localStorage.setItem(this.STORAGE_KEY_FOLDERS, JSON.stringify(filtered));
    } catch {
      throw new Error('Não foi possível deletar a pasta');
    }
  }

  clearAllChats(): void {
    localStorage.removeItem(this.STORAGE_KEY_CHATS);
  }

  clearAllFolders(): void {
    localStorage.removeItem(this.STORAGE_KEY_FOLDERS);
  }

  async sendMessage(request: ChatMessageRequest): Promise<ChatResponse> {
    const { chatId, message, modelId, personalidade, anexos } = request;

    if (!chatId) throw { success: false, message: 'ID do chat é obrigatório' };
    if (!message?.trim()) throw { success: false, message: 'A mensagem não pode estar vazia' };
    if (!modelId) throw { success: false, message: 'Modelo da IA é obrigatório' };
    if (anexos && anexos.length > this.MAX_ATTACHMENTS) {
      throw { success: false, message: `Máximo de ${this.MAX_ATTACHMENTS} arquivos anexos permitidos` };
    }

    const email = GlobalFunctions.getTransferProperty(TransferAreaProperties.UsuarioEmail);
    const estabId = GlobalFunctions.getTransferProperty(TransferAreaProperties.EstabelecimentoCodigo);

    const formData = new FormData();
    formData.append('estabelecimento_id', estabId.toString());
    formData.append('chat_id', chatId);
    formData.append('user_email', email);
    formData.append('model_id', modelId);
    formData.append('message', message);

    if (personalidade?.trim()) {
      formData.append('personalidade', personalidade);
    }

    anexos?.forEach((file, i) => {
      if (i < this.MAX_ATTACHMENTS) formData.append(`anexo${i + 1}`, file);
    });

    try {
      const response = await apiService.postFormData<ChatResponse>(this.CHAT_ENDPOINT, formData);
      return response.data;
    } catch (error: unknown) {
      console.error('Erro ao enviar mensagem:', error);
      this.toApiError(error, 'Erro ao comunicar com a IA');
    }
  }

  async createFolder(name: string, userEmail?: string): Promise<{ success: boolean }> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };
    if (!name?.trim()) throw { success: false, message: 'Nome da pasta não pode estar vazio' };

    try {
      const response = await apiService.post<ApiArrayResult>(
        this.POST_FOLDER_ENDPOINT,
        { user_email: email, name: name.trim() }
      );
      const result = this.firstResult(response.data);
      return { success: result.success ?? true };
    } catch (error: unknown) {
      console.error('Erro ao criar pasta:', error);
      this.toApiError(error, 'Erro ao criar pasta');
    }
  }

  async renameFolder(folderId: string, newName: string, userEmail?: string): Promise<{ success: boolean }> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };
    if (!folderId?.trim()) throw { success: false, message: 'ID da pasta não pode estar vazio' };
    if (!newName?.trim()) throw { success: false, message: 'Nome da pasta não pode estar vazio' };

    try {
      const response = await apiService.put<ApiArrayResult>(
        this.POST_FOLDER_ENDPOINT,
        { id: folderId, user_email: email, name: newName.trim() }
      );
      const result = this.firstResult(response.data);
      return { success: result.success ?? true };
    } catch (error: unknown) {
      console.error('Erro ao renomear pasta:', error);
      this.toApiError(error, 'Erro ao renomear pasta');
    }
  }

  async getChatsAndFolders(userEmail?: string): Promise<GetChatsAndFoldersResponse> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };

    try {
      const response = await apiService.get<Array<{ result: GetChatsAndFoldersResponse }>>(
        `${this.GET_CHATS_FOLDERS_ENDPOINT}/${email}`
      );

      let result: GetChatsAndFoldersResponse;
      const data = response.data;

      if (Array.isArray(data) && data.length > 0) {
        result = data[0].result;
      } else if (data && typeof data === 'object' && 'result' in data) {
        result = (data as { result: GetChatsAndFoldersResponse }).result;
      } else {
        result = { chats: [], folders: [] };
      }

      return {
        chats: Array.isArray(result.chats) ? result.chats : [],
        folders: Array.isArray(result.folders) ? result.folders : [],
      };
    } catch (error: unknown) {
      console.error('Erro ao buscar chats e pastas:', error);
      this.toApiError(error, 'Erro ao buscar chats e pastas');
    }
  }

  async moveChatToFolder(chatId: string, folderId: string): Promise<{ success: boolean }> {
    if (!chatId || !folderId) {
      throw { success: false, message: 'Chat ID e Folder ID são obrigatórios' };
    }

    try {
      const response = await apiService.put<ApiArrayResult>(
        `${this.PUT_CHAT_IN_FOLDER_ENDPOINT}/${folderId}/${chatId}`
      );
      const result = this.firstResult(response.data);
      return { success: result.success ?? true };
    } catch (error: unknown) {
      console.error('Erro ao mover chat para pasta:', error);
      this.toApiError(error, 'Erro ao mover chat para pasta');
    }
  }

  async deleteFolder(folderId: string, userEmail?: string): Promise<{ success: boolean }> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };
    if (!folderId) throw { success: false, message: 'ID da pasta não fornecido' };

    try {
      const response = await apiService.delete<ApiArrayResult>(
        `${this.DELETE_FOLDER_ENDPOINT}/${email}/${folderId}`
      );
      const result = this.firstResult(response.data);
      return { success: result.success ?? true };
    } catch (error: unknown) {
      console.error('Erro ao deletar pasta:', error);
      this.toApiError(error, 'Erro ao deletar pasta');
    }
  }

  async deleteChat(chatId: string, userEmail?: string): Promise<{ success: boolean }> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };
    if (!chatId) throw { success: false, message: 'ID do chat não fornecido' };

    try {
      const response = await apiService.delete<ApiArrayResult>(
        `${this.DELETE_CHAT_ENDPOINT}/${email}/${chatId}`
      );
      const result = this.firstResult(response.data);
      return { success: result.success ?? true };
    } catch (error: unknown) {
      console.error('Erro ao deletar chat:', error);
      this.toApiError(error, 'Erro ao deletar chat');
    }
  }

  async getChatMessages(chatId: string, userEmail?: string): Promise<MessageRecord[]> {
    const email = this.resolveEmail(userEmail);
    if (!email) throw { success: false, message: 'Email do usuário não fornecido' };
    if (!chatId) throw { success: false, message: 'ID do chat não fornecido' };

    try {
      const response = await apiService.get<unknown>(
        `${this.GET_CHAT_MESSAGES_ENDPOINT}/${email}/${chatId}`
      );
      return this.extractArray<MessageRecord>(response.data, ['messages', 'data']);
    } catch (error: unknown) {
      console.error('Erro ao buscar mensagens:', error);
      this.toApiError(error, 'Erro ao buscar mensagens');
    }
  }
}

export const chatService = new ChatService();
