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

const defaultRepositoryItemTypes: Record<
  string,
  {
    name: string;
    description: string;
    supportsFile: boolean;
    supportsText: boolean;
  }
> = {
  email: {
    name: "Email",
    description: "Inbound or outbound email",
    supportsFile: false,
    supportsText: true,
  },
  phone_call: {
    name: "Phone Call",
    description: "Phone call summary or transcript",
    supportsFile: false,
    supportsText: true,
  },
  whatsapp_message: {
    name: "WhatsApp Message",
    description: "WhatsApp conversation message",
    supportsFile: false,
    supportsText: true,
  },
  form_submission: {
    name: "Form Submission",
    description: "Submitted intake or portal form",
    supportsFile: false,
    supportsText: true,
  },
  document: {
    name: "Document",
    description: "Uploaded document or evidence file",
    supportsFile: true,
    supportsText: true,
  },
  image: {
    name: "Image",
    description: "Image file linked to the case",
    supportsFile: true,
    supportsText: false,
  },
  audio: {
    name: "Audio",
    description: "Audio file or recording",
    supportsFile: true,
    supportsText: false,
  },
  video: {
    name: "Video",
    description: "Video file",
    supportsFile: true,
    supportsText: false,
  },
  note: {
    name: "Note",
    description: "Internal note",
    supportsFile: false,
    supportsText: true,
  },
  extracted_fact: {
    name: "Extracted Fact",
    description: "Structured fact derived from sources",
    supportsFile: false,
    supportsText: true,
  },
  client_profile_summary: {
    name: "Client Profile Summary",
    description: "AI-synthesized client knowledge summary for downstream form filling",
    supportsFile: false,
    supportsText: true,
  },
  generated_form: {
    name: "Generated Form",
    description: "AI or system-generated filled form",
    supportsFile: true,
    supportsText: true,
  },
  final_packet: {
    name: "Final Packet",
    description: "Compiled final filing packet",
    supportsFile: true,
    supportsText: true,
  },
  questionnaire_answer: {
    name: "Questionnaire Answer",
    description: "Client answer from intelligent questionnaire",
    supportsFile: false,
    supportsText: true,
  },
  ai_gap_analysis: {
    name: "AI Gap Analysis",
    description: "Gap analysis run artifact",
    supportsFile: false,
    supportsText: true,
  },
  client_portal_chat: {
    name: "Client Portal Chat",
    description: "Portal chat message",
    supportsFile: false,
    supportsText: true,
  },
};

async function ensureRepositoryItemTypeExists(itemTypeCode: string) {
  const defaultType = defaultRepositoryItemTypes[itemTypeCode];

  if (!defaultType) {
    return;
  }

  await prisma.$executeRaw`
    INSERT IGNORE INTO repository_item_types (
      code,
      name,
      description,
      supports_file,
      supports_text
    ) VALUES (
      ${itemTypeCode},
      ${defaultType.name},
      ${defaultType.description},
      ${defaultType.supportsFile ? 1 : 0},
      ${defaultType.supportsText ? 1 : 0}
    )
  `;
}

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 ensureRepositoryItemTypeExists(input.itemTypeCode);

  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}
  `;
}
