import {
  DELETED_MESSAGE_CONTENT,
  type Message,
  type MessageRevision,
  type MessageRevisionType
} from '../../../../shared-kernel';
import {
  buildMessageHeadState,
  computeMessageHeadHash,
  getMessageRevision,
  resolveMessageRevision
} from './message-integrity.rules';
import { getMessageTimestamp } from './message.rules';

export interface BuildMessageRevisionInput {
  message: Message;
  type: MessageRevisionType;
  actorId: string;
  content?: string;
  editedAt: number;
  isDeleted?: boolean;
  pluginId?: string;
  prevRevisionHash?: string;
  signature?: string;
}

export async function buildMessageRevision(input: BuildMessageRevisionInput): Promise<MessageRevision> {
  const revision = input.type === 'create'
    ? 0
    : resolveMessageRevision(input.message, input.type);
  const isDeleted = input.isDeleted ?? input.type.includes('delete');
  const content = isDeleted
    ? DELETED_MESSAGE_CONTENT
    : (input.content ?? input.message.content);
  const materializedMessage: Message = {
    ...input.message,
    content,
    editedAt: input.editedAt,
    isDeleted,
    revision
  };
  const headHash = await computeMessageHeadHash(buildMessageHeadState(materializedMessage, revision));

  return {
    messageId: input.message.id,
    revision,
    prevRevisionHash: input.prevRevisionHash ?? '',
    headHash,
    type: input.type,
    actorId: input.actorId,
    senderId: input.message.senderId,
    roomId: input.message.roomId,
    channelId: input.message.channelId,
    senderName: input.message.senderName,
    content,
    editedAt: input.editedAt,
    isDeleted,
    replyToId: input.message.replyToId,
    pluginId: input.pluginId,
    signature: input.signature
  };
}

export function materializeMessageFromRevision(
  existing: Message | null,
  revision: MessageRevision
): Message {
  const base = existing ?? {
    id: revision.messageId,
    roomId: revision.roomId,
    channelId: revision.channelId,
    senderId: revision.senderId,
    senderName: revision.senderName ?? 'Unknown',
    content: revision.content ?? '',
    timestamp: revision.editedAt,
    reactions: [],
    isDeleted: revision.isDeleted,
    replyToId: revision.replyToId
  };

  return {
    ...base,
    roomId: revision.roomId,
    channelId: revision.channelId ?? base.channelId,
    senderId: revision.senderId,
    senderName: revision.senderName ?? base.senderName,
    content: revision.isDeleted ? DELETED_MESSAGE_CONTENT : (revision.content ?? base.content),
    editedAt: revision.type === 'create' ? undefined : revision.editedAt,
    revision: revision.revision,
    headHash: revision.headHash,
    isDeleted: revision.isDeleted,
    replyToId: revision.replyToId ?? base.replyToId
  };
}

export function revisionTimestamp(revision: MessageRevision): number {
  return revision.editedAt;
}

export function revisionBeatsMessage(revision: MessageRevision, message: Message | null): boolean {
  const existingRevision = getMessageRevision(message ?? undefined);

  if (revision.revision !== existingRevision) {
    return revision.revision > existingRevision;
  }

  return revision.headHash !== message?.headHash;
}
