import { prisma } from "./prisma.js";
import { createId } from "./id.js";

export async function createRepositoryItem(input: {
  lawFirmId: string;
  clientId?: string | null;
  caseId?: string | null;
  itemTypeCode: string;
  channelCode?: string | null;
  sourceEntityType?: string | null;
  sourceEntityId?: string | null;
  directionCode?: string | null;
  subject?: string | null;
  bodyText?: string | null;
  summaryText?: string | null;
  metadataJson?: unknown;
  authoredByUserId?: string | null;
  createdByUserId?: string | null;
  externalReference?: string | null;
  occurredAt?: Date | null;
}) {
  const id = createId();

  await prisma.$executeRaw`
    INSERT INTO repository_items (
      id, law_firm_id, client_id, case_id, item_type_code, channel_code, source_entity_type,
      source_entity_id, direction_code, subject, body_text, summary_text, metadata_json,
      authored_by_user_id, created_by_user_id, external_reference, occurred_at, created_at, updated_at
    ) VALUES (
      ${id},
      ${input.lawFirmId},
      ${input.clientId ?? null},
      ${input.caseId ?? null},
      ${input.itemTypeCode},
      ${input.channelCode ?? null},
      ${input.sourceEntityType ?? null},
      ${input.sourceEntityId ?? null},
      ${input.directionCode ?? null},
      ${input.subject ?? null},
      ${input.bodyText ?? null},
      ${input.summaryText ?? null},
      ${input.metadataJson ? JSON.stringify(input.metadataJson) : null},
      ${input.authoredByUserId ?? null},
      ${input.createdByUserId ?? null},
      ${input.externalReference ?? null},
      ${input.occurredAt ?? new Date()},
      CURRENT_TIMESTAMP,
      CURRENT_TIMESTAMP
    )
  `;

  return id;
}

export async function createConversation(input: {
  lawFirmId: string;
  clientId: string;
  caseId?: string | null;
  channelCode: string;
  subject?: string | null;
  participantsJson?: unknown;
  externalThreadId?: string | null;
}) {
  const id = createId();

  await prisma.$executeRaw`
    INSERT INTO conversations (
      id, law_firm_id, client_id, case_id, channel_code, subject, participants_json,
      external_thread_id, started_at, created_at, updated_at
    ) VALUES (
      ${id},
      ${input.lawFirmId},
      ${input.clientId},
      ${input.caseId ?? null},
      ${input.channelCode},
      ${input.subject ?? null},
      ${input.participantsJson ? JSON.stringify(input.participantsJson) : null},
      ${input.externalThreadId ?? null},
      NOW(),
      CURRENT_TIMESTAMP,
      CURRENT_TIMESTAMP
    )
  `;

  return id;
}

export async function storeConversationMessage(input: {
  lawFirmId: string;
  clientId: string;
  caseId?: string | null;
  conversationId?: string | null;
  channelCode: string;
  itemTypeCode: string;
  directionCode: string;
  subject?: string | null;
  bodyText: string;
  senderType?: string;
  senderName?: string | null;
  senderAddress?: string | null;
  recipientAddress?: string | null;
  authoredByUserId?: string | null;
  createdByUserId?: string | null;
  externalReference?: string | null;
  externalMessageId?: string | null;
  messageStatus?: string | null;
  occurredAt?: Date | null;
  conversationSubject?: string | null;
  conversationParticipantsJson?: unknown;
  conversationExternalThreadId?: string | null;
}) {
  const conversationId =
    input.conversationId ??
    (await createConversation({
      lawFirmId: input.lawFirmId,
      clientId: input.clientId,
      caseId: input.caseId ?? null,
      channelCode: input.channelCode,
      subject: input.conversationSubject ?? input.subject ?? null,
      participantsJson: input.conversationParticipantsJson,
      externalThreadId: input.conversationExternalThreadId ?? null,
    }));

  const repositoryItemId = await createRepositoryItem({
    lawFirmId: input.lawFirmId,
    clientId: input.clientId,
    caseId: input.caseId ?? null,
    itemTypeCode: input.itemTypeCode,
    channelCode: input.channelCode,
    directionCode: input.directionCode,
    subject: input.subject ?? null,
    bodyText: input.bodyText,
    authoredByUserId: input.authoredByUserId ?? null,
    createdByUserId: input.createdByUserId ?? null,
    sourceEntityType: "conversation",
    sourceEntityId: conversationId,
    externalReference: input.externalReference ?? null,
    occurredAt: input.occurredAt ?? null,
  });

  const messageId = createId();

  await prisma.$executeRaw`
    INSERT INTO messages (
      id, law_firm_id, conversation_id, repository_item_id, sender_type, sender_name,
      sender_address, recipient_address, message_direction, external_message_id,
      message_status, sent_at, created_at
    ) VALUES (
      ${messageId},
      ${input.lawFirmId},
      ${conversationId},
      ${repositoryItemId},
      ${input.senderType ?? "person"},
      ${input.senderName ?? null},
      ${input.senderAddress ?? null},
      ${input.recipientAddress ?? null},
      ${input.directionCode},
      ${input.externalMessageId ?? null},
      ${input.messageStatus ?? "stored"},
      ${input.occurredAt ?? new Date()},
      CURRENT_TIMESTAMP
    )
  `;

  return {
    messageId,
    conversationId,
    repositoryItemId,
  };
}

export async function updateConversationMessageStatus(input: {
  lawFirmId: string;
  repositoryItemId: string;
  messageStatus: string;
}) {
  await prisma.$executeRaw`
    UPDATE messages
    SET
      message_status = ${input.messageStatus}
    WHERE law_firm_id = ${input.lawFirmId}
      AND repository_item_id = ${input.repositoryItemId}
  `;
}
