import { Message } from '@api/chat/chat-api';
import { MMKV } from 'react-native-mmkv';
import axios from 'axios';
import { API } from 'src/types';
import { API_URL, APP_VERSION } from 'src/constants';
import { Platform } from 'react-native';

type CustomMessage = Message & { reply_to: Message };

const storageMMKV = new MMKV();

const get = (key: string, type: StoreType) => {
  switch (type) {
    case StoreType.STRING:
      return storageMMKV.getString(key);
    case StoreType.BOOLEAN:
      return storageMMKV.getBoolean(key);
    case StoreType.NUMBER:
      return storageMMKV.getNumber(key);
  }
};

const set = (key: string, value: string | boolean | number) => {
  storageMMKV.set(key, value);
};

const remove = (key: string) => {
  storageMMKV.delete(key);
};

export const storage = { get, set, remove, getAllKeys: () => storageMMKV.getAllKeys() };

export enum StoreType {
  STRING = 'string',
  NUMBER = 'number',
  BOOLEAN = 'boolean'
}

export function loadData<T>(nameKey: string, key: string): T | null {
  const namespacedKey = `${nameKey}:${key}`;
  const jsonData = storage.get(namespacedKey, StoreType.STRING) as string;

  return jsonData ? JSON.parse(jsonData) : null;
}

export const saveMessagesToStorage = (chatId: string | number, data: any) => {
  storage.set(`chat_${chatId}`, JSON.stringify(data));
  storage.set(`chat_${chatId}_updatedAt`, Date.now());
};

export const editMessageInStorage = (
  chatId: string | number,
  messageId: number,
  newText: string,
  isGroup: boolean
) => {
  const storedMessages = storage.get(`chat_${chatId}`, StoreType.STRING) as string;
  if (!storedMessages) return;

  const data = JSON.parse(storedMessages);
  const messages = isGroup ? data.messages : data;
  const updatedMessages = messages.map((msg: Message) =>
    msg.id === messageId ? { ...msg, text: newText, edits: '{[]}' } : msg
  );

  storage.set(`chat_${chatId}`, JSON.stringify(updatedMessages));
};

export const sendMessageOffline = (chatId: string | number, message: Message) => {
  const unsentMessages = storage.get(`unsent_${chatId}`, StoreType.STRING)
    ? JSON.parse(storage.get(`unsent_${chatId}`, StoreType.STRING) as string)
    : [];
  unsentMessages.push(message);
  storage.set(`unsent_${chatId}`, JSON.stringify(unsentMessages));
};

export const checkAndSendSavedMessages = async () => {
  const token = storage.get('token', StoreType.STRING) as string;
  const chatKeys = storage.getAllKeys().filter((key) => key.startsWith('unsent_'));

  for (const key of chatKeys) {
    const chatId = key.replace('unsent_', '');
    let unsentMessages = JSON.parse((storage.get(key, StoreType.STRING) as string) || '[]');

    const successfullySent: any[] = [];

    for (const message of unsentMessages) {
      try {
        if (!message || !message.text) continue;

        let response;
        if (!isNaN(+chatId)) {
          response = await axios.postForm(
            API_URL + '/' + API.SEND_MESSAGE,
            {
              token,
              to_uid: chatId,
              text: message.text,
              reply_to_id: message.reply_to_id ? (message.reply_to_id as number) : -1
            },
            {
              headers: {
                Platform: Platform.OS,
                'App-Version': APP_VERSION
              }
            }
          );
        } else {
          response = await axios.postForm(
            API_URL + '/' + API.SEND_GROUP_MESSAGE,
            {
              token,
              to_group_token: chatId,
              text: message.text,
              reply_to_id: message.reply_to_id ? (message.reply_to_id as number) : -1
            },
            {
              headers: {
                Platform: Platform.OS,
                'App-Version': APP_VERSION
              }
            }
          );
        }

        if (response?.data?.result === 'OK') {
          successfullySent.push(message.id);
        }
      } catch (error) {
        console.error('Error checkAndSendSavedMessages func', message);
      }
    }

    unsentMessages = unsentMessages.filter((msg: any) => !successfullySent.includes(msg.id));

    if (unsentMessages.length > 0) {
      storage.set(key, JSON.stringify(unsentMessages));
    } else {
      storage.remove(key);
    }
  }
};

const getStorageSize = () => {
  const keys = storage
    .getAllKeys()
    .filter((key) => key.startsWith('chat_') && !key.endsWith('_updatedAt'));
  let totalSize = 0;

  keys.forEach((key) => {
    const value = storage.get(key, StoreType.STRING) as string;
    if (value) {
      totalSize += new Blob([value]).size;
    }
  });

  return totalSize;
};

export const enforceStorageLimit = () => {
  let totalSize = getStorageSize();
  const maxSize = 5 * 1024 * 1024;

  if (totalSize > maxSize) {
    const chatKeys = storage
      .getAllKeys()
      .filter((key) => key.startsWith('chat_') && !key.endsWith('_updatedAt'));

    const chatTimestamps = chatKeys.map((chatKey) => ({
      chatKey,
      updatedAt: (storage.get(`${chatKey}_updatedAt`, StoreType.NUMBER) as number) || 0
    }));

    chatTimestamps.sort((a, b) => a.updatedAt - b.updatedAt);

    for (const chat of chatTimestamps) {
      storage.remove(chat.chatKey);
      storage.remove(`${chat.chatKey}_updatedAt`);

      totalSize = getStorageSize();
      if (totalSize <= maxSize) break;
    }
  }
};
