'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { ChatMessage, ChatRoom, fetchUserE2EPublicKey, setUserE2EPublicKey } from '@/lib/api';
import { ensureE2EKeyPair } from '@/lib/e2e-crypto';
import {
  decryptE2EPayload,
  encryptE2EPayload,
  readableE2EPayload,
  type E2EMessagePayload
} from '@/lib/e2e-chat';

export function resolveChatPeerUserId(room: ChatRoom | null | undefined, userId: string | undefined) {
  if (!room || !userId) return null;
  const fromMembers = room.members.find((member) => member.userId !== userId)?.userId;
  if (fromMembers) return fromMembers;
  if (room.peerUserId && room.peerUserId !== userId) return room.peerUserId;
  return null;
}

export function getE2EMessageText(options: {
  message: ChatMessage;
  isE2E: boolean;
  peerE2eKey: string | null;
  peerKeyLoading: boolean;
  e2ePayload?: E2EMessagePayload | null;
  e2eError?: string;
}) {
  const { message, isE2E, peerE2eKey, peerKeyLoading, e2ePayload, e2eError } = options;
  if (!message.isEncrypted) {
    return message.content ?? '';
  }
  if (e2ePayload) {
    return readableE2EPayload(e2ePayload);
  }
  if (e2eError) {
    return e2eError;
  }
  if (isE2E && peerKeyLoading) {
    return '🔒 Расшифровка...';
  }
  if (isE2E && !peerE2eKey) {
    return '🔒 Собеседник не опубликовал ключ шифрования';
  }
  return '🔒 Расшифровка...';
}

export function useE2EChat(options: {
  room: ChatRoom | null | undefined;
  messages: ChatMessage[];
  userId?: string;
  token?: string | null;
}) {
  const isE2E = options.room?.type === 'E2E';
  const peerUserId = useMemo(
    () => resolveChatPeerUserId(options.room, options.userId),
    [options.room, options.userId]
  );

  const [peerE2eKey, setPeerE2eKey] = useState<string | null>(null);
  const [peerKeyLoading, setPeerKeyLoading] = useState(false);
  const [e2ePayloads, setE2ePayloads] = useState<Record<string, E2EMessagePayload | null>>({});
  const [e2eErrors, setE2eErrors] = useState<Record<string, string>>({});

  useEffect(() => {
    if (!options.userId || !options.token) return;
    void (async () => {
      try {
        const { publicKey } = await ensureE2EKeyPair(options.userId!);
        await setUserE2EPublicKey(options.userId!, publicKey, options.token);
      } catch {
        // фоновая инициализация E2E
      }
    })();
  }, [options.token, options.userId]);

  useEffect(() => {
    if (!isE2E || !peerUserId || !options.token) {
      setPeerE2eKey(null);
      setPeerKeyLoading(false);
      return;
    }
    setPeerKeyLoading(true);
    void fetchUserE2EPublicKey(peerUserId, options.token)
      .then((response) => setPeerE2eKey(response.e2ePublicKey ?? null))
      .catch(() => setPeerE2eKey(null))
      .finally(() => setPeerKeyLoading(false));
  }, [isE2E, options.token, peerUserId]);

  useEffect(() => {
    if (!isE2E || !peerE2eKey || !options.userId) {
      setE2ePayloads({});
      setE2eErrors({});
      return;
    }

    let cancelled = false;
    void (async () => {
      const nextPayloads: Record<string, E2EMessagePayload | null> = {};
      const nextErrors: Record<string, string> = {};

      for (const message of options.messages) {
        if (!message.isEncrypted || !message.content) continue;
        const payload = await decryptE2EPayload(options.userId!, peerE2eKey, message.content);
        if (payload) {
          nextPayloads[message.id] = payload;
        } else {
          nextErrors[message.id] = '🔒 Не удалось расшифровать сообщение';
        }
      }

      if (!cancelled) {
        setE2ePayloads(nextPayloads);
        setE2eErrors(nextErrors);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [isE2E, options.messages, options.userId, peerE2eKey]);

  const encryptOutgoing = useCallback(
    async (payload: Parameters<typeof encryptE2EPayload>[2]) => {
      if (!isE2E || !options.userId) {
        throw new Error('E2E недоступен');
      }
      if (!peerE2eKey) {
        throw new Error('Собеседник ещё не опубликовал ключ шифрования');
      }
      return encryptE2EPayload(options.userId, peerE2eKey, payload);
    },
    [isE2E, options.userId, peerE2eKey]
  );

  return {
    isE2E,
    peerUserId,
    peerE2eKey,
    peerKeyLoading,
    e2ePayloads,
    e2eErrors,
    encryptOutgoing
  };
}
