/**
 * Support Domain - Salesforce Provider Mapper
 *
 * Transform functions to convert raw Salesforce Case records to domain types.
 */

import {
  supportCaseSchema,
  caseMessageSchema,
  type SupportCase,
  type CaseMessage,
} from "../../schema.js";
import type {
  SalesforceCaseRecord,
  SalesforceEmailMessage,
  SalesforceCaseComment,
} from "./raw.types.js";
import {
  getStatusDisplayLabel,
  getPriorityDisplayLabel,
  SALESFORCE_CASE_STATUS,
  SALESFORCE_CASE_PRIORITY,
} from "./raw.types.js";

// ============================================================================
// Helper Functions
// ============================================================================

/**
 * Safely coerce a value to string or return undefined
 */
function ensureString(value: unknown): string | undefined {
  if (typeof value === "string" && value.length > 0) {
    return value;
  }
  return undefined;
}

/**
 * Get current ISO timestamp
 */
function nowIsoString(): string {
  return new Date().toISOString();
}

// ============================================================================
// Email Body Cleaning
// ============================================================================

/**
 * Multi-line patterns to remove from email body FIRST (before line-by-line processing).
 * These patterns can span multiple lines and should be removed entirely.
 *
 * Order matters - more specific patterns should come first.
 */
const MULTILINE_QUOTE_PATTERNS: RegExp[] = [
  // Gmail multi-line: "On <date> ... <email>\nwrote:" or "On <date> ... <name> <\nemail> wrote:"
  // This handles cases where the email address or "wrote:" wraps to next line
  /On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)[^]*?wrote:\s*/gi,

  // Generic "On <date> <name> wrote:" that may span lines
  /On\s+\d{1,2}[^]*?wrote:\s*/gi,

  // Japanese: "<date>に<name>が書きました:"
  /\d{4}[年/-]\d{1,2}[月/-]\d{1,2}[日]?[^]*?書きました[:：]\s*/g,

  // "---- Original Message ----" and everything after
  /-{2,}\s*(?:Original\s*Message|Forwarded|転送|元のメッセージ)[^]*/gi,

  // "___" Outlook separator and everything after
  /_{3,}[^]*/g,

  // "From: <email>" header block (usually indicates quoted content start)
  // Only match if it's followed by typical email header patterns
  /\nFrom:\s*[^\n]+\n(?:Sent|To|Date|Subject|Cc):[^]*/gi,
];

/**
 * Single-line patterns that indicate the start of quoted content.
 * Once matched, all remaining lines are discarded.
 */
const QUOTE_START_LINE_PATTERNS: RegExp[] = [
  // "> quoted text" at start of line
  /^>/,
  // "From:" at start of line (email header)
  /^From:\s+.+/i,
  // "送信者:" (Japanese: Sender)
  /^送信者[:：]\s*.+/,
  // "Sent:" header
  /^Sent:\s+.+/i,
  // Date/Time headers appearing mid-email
  /^(Date|日時|送信日時)[:：]\s+.+/i,
  // "Subject:" appearing mid-email
  /^(Subject|件名)[:：]\s+.+/i,
  // "To:" appearing mid-email (not at very start)
  /^(To|宛先)[:：]\s+.+/i,
  // Lines that look like "wrote:" endings we might have missed
  /^\s*wrote:\s*$/i,
  /^\s*書きました[:：]?\s*$/,
  // Email in angle brackets followed by wrote (continuation line)
  /^[^<]*<[^>]+>\s*wrote:\s*$/i,
];

/**
 * Patterns for lines to skip (metadata) but continue processing
 */
const SKIP_LINE_PATTERNS: RegExp[] = [
  /^(Cc|CC|Bcc|BCC)[:：]\s*.*/i,
  /^(Reply-To|返信先)[:：]\s*.*/i,
];

/**
 * Clean email body by removing quoted/forwarded content.
 *
 * This function strips out:
 * - Quoted replies (lines starting with ">")
 * - "On <date>, <name> wrote:" blocks (including multi-line Gmail format)
 * - "From: / To: / Subject:" quoted headers
 * - "-------- Original Message --------" separators
 * - Japanese equivalents of the above
 *
 * @param body - Raw email text body
 * @returns Cleaned email body with only the latest reply content
 */
export function cleanEmailBody(body: string): string {
  if (!body) return "";

  let cleaned = body;

  // Step 1: Apply multi-line pattern removal first
  for (const pattern of MULTILINE_QUOTE_PATTERNS) {
    cleaned = cleaned.replace(pattern, "");
  }

  // Step 2: Process line by line for remaining patterns
  const lines = cleaned.split(/\r?\n/);
  const cleanLines: string[] = [];
  let foundQuoteStart = false;

  for (const line of lines) {
    if (foundQuoteStart) {
      // Already in quoted section, skip all remaining lines
      continue;
    }

    const trimmedLine = line.trim();

    // Check if this line starts quoted content
    const isQuoteStart = QUOTE_START_LINE_PATTERNS.some(pattern => pattern.test(trimmedLine));
    if (isQuoteStart) {
      foundQuoteStart = true;
      continue;
    }

    // Skip metadata lines but continue processing
    const isSkipLine = SKIP_LINE_PATTERNS.some(pattern => pattern.test(trimmedLine));
    if (isSkipLine) {
      continue;
    }

    cleanLines.push(line);
  }

  // Step 3: Clean up the result
  let result = cleanLines.join("\n");

  // Remove excessive trailing whitespace/newlines
  result = result.replace(/\s+$/, "");

  // Remove leading blank lines
  result = result.replace(/^\s*\n+/, "");

  // If we stripped everything, return original (edge case)
  if (!result.trim()) {
    // Try to extract at least something useful from original
    const firstParagraph = body.split(/\n\s*\n/)[0]?.trim();
    return firstParagraph || body.slice(0, 500);
  }

  return result;
}

// ============================================================================
// Transform Functions
// ============================================================================

/**
 * Transform a raw Salesforce Case record to a portal SupportCase.
 *
 * Converts Salesforce API values (often in Japanese) to portal display labels (English).
 *
 * @param record - Raw Salesforce Case record from SOQL query
 * @returns Validated SupportCase domain object
 */
export function transformSalesforceCaseToSupportCase(record: SalesforceCaseRecord): SupportCase {
  // Get raw values
  const rawStatus = ensureString(record.Status) ?? SALESFORCE_CASE_STATUS.NEW;
  const rawPriority = ensureString(record.Priority) ?? SALESFORCE_CASE_PRIORITY.MEDIUM;

  return supportCaseSchema.parse({
    id: record.Id,
    caseNumber: record.CaseNumber,
    subject: ensureString(record.Subject) ?? "",
    // Convert Japanese SF values to English display labels
    status: getStatusDisplayLabel(rawStatus),
    priority: getPriorityDisplayLabel(rawPriority),
    category: ensureString(record.Type) ?? null,
    description: ensureString(record.Description) ?? "",
    createdAt: ensureString(record.CreatedDate) ?? nowIsoString(),
    updatedAt: ensureString(record.LastModifiedDate) ?? nowIsoString(),
    closedAt: ensureString(record.ClosedDate) ?? null,
  });
}

/**
 * Transform multiple Salesforce Case records to SupportCase array.
 *
 * @param records - Array of raw Salesforce Case records
 * @returns Array of validated SupportCase domain objects
 */
export function transformSalesforceCasesToSupportCases(
  records: SalesforceCaseRecord[]
): SupportCase[] {
  return records.map(transformSalesforceCaseToSupportCase);
}

/**
 * Build the SOQL SELECT fields for Case queries.
 *
 * Standard Salesforce Case fields based on org configuration.
 * Note: Type field is not accessible via API in this org.
 *
 * @param additionalFields - Optional additional fields to include
 * @returns Array of field names for SOQL SELECT clause
 */
export function buildCaseSelectFields(additionalFields: string[] = []): string[] {
  const baseFields = [
    // Core identifiers
    "Id",
    "CaseNumber",

    // Case content
    "Subject",
    "Description",

    // Picklist fields
    "Status",
    "Priority",
    "Origin",

    // Relationships
    "AccountId",
    "ContactId",
    "OwnerId",

    // Timestamps
    "CreatedDate",
    "LastModifiedDate",
    "ClosedDate",

    // Flags
    "IsEscalated",
  ];

  return [...new Set([...baseFields, ...additionalFields])];
}

/**
 * Build a SOQL query for fetching cases for an account.
 *
 * @param accountId - Salesforce Account ID
 * @param origin - Case origin to filter by (e.g., "Portal Support")
 * @param additionalFields - Optional additional fields to include
 * @returns SOQL query string
 */
export function buildCasesForAccountQuery(
  accountId: string,
  origin: string,
  additionalFields: string[] = []
): string {
  const fields = buildCaseSelectFields(additionalFields).join(", ");
  return `
    SELECT ${fields}
    FROM Case
    WHERE AccountId = '${accountId}' AND Origin = '${origin}'
    ORDER BY CreatedDate DESC
    LIMIT 100
  `.trim();
}

/**
 * Build a SOQL query for fetching a single case by ID.
 *
 * @param caseId - Salesforce Case ID
 * @param accountId - Salesforce Account ID (for ownership validation)
 * @param origin - Case origin to filter by
 * @param additionalFields - Optional additional fields to include
 * @returns SOQL query string
 */
export function buildCaseByIdQuery(
  caseId: string,
  accountId: string,
  origin: string,
  additionalFields: string[] = []
): string {
  const fields = buildCaseSelectFields(additionalFields).join(", ");
  return `
    SELECT ${fields}
    FROM Case
    WHERE Id = '${caseId}' AND AccountId = '${accountId}' AND Origin = '${origin}'
    LIMIT 1
  `.trim();
}

// ============================================================================
// EmailMessage Transform Functions
// ============================================================================

/**
 * Build the SOQL SELECT fields for EmailMessage queries.
 */
export function buildEmailMessageSelectFields(): string[] {
  return [
    "Id",
    "ParentId",
    "Subject",
    "TextBody",
    "HtmlBody",
    "FromAddress",
    "FromName",
    "ToAddress",
    "Incoming",
    "Status",
    "MessageDate",
    "CreatedDate",
    "HasAttachment",
  ];
}

/**
 * Build SOQL query for fetching EmailMessages for a Case.
 */
export function buildEmailMessagesForCaseQuery(caseId: string): string {
  const fields = buildEmailMessageSelectFields().join(", ");
  return `
    SELECT ${fields}
    FROM EmailMessage
    WHERE ParentId = '${caseId}'
    ORDER BY MessageDate ASC
  `.trim();
}

/**
 * Transform a Salesforce EmailMessage to a unified CaseMessage.
 *
 * Cleans the email body to show only the latest reply, stripping out
 * quoted content and previous email chains for a cleaner conversation view.
 *
 * @param email - Raw Salesforce EmailMessage
 * @param customerEmail - Customer's email address for comparison
 */
export function transformEmailMessageToCaseMessage(
  email: SalesforceEmailMessage,
  customerEmail?: string
): CaseMessage {
  const isIncoming = email.Incoming === true;
  const fromEmail = ensureString(email.FromAddress);
  const fromName = ensureString(email.FromName) ?? fromEmail ?? "Unknown";

  // Determine if this is from the customer
  // Incoming emails are from customer, or check email match
  const isCustomer =
    isIncoming ||
    (customerEmail ? fromEmail?.toLowerCase() === customerEmail.toLowerCase() : false);

  // Get the raw email body and clean it (strip quoted content)
  const rawBody = ensureString(email.TextBody) ?? ensureString(email.HtmlBody) ?? "";
  const cleanedBody = cleanEmailBody(rawBody);

  return caseMessageSchema.parse({
    id: email.Id,
    type: "email",
    body: cleanedBody,
    author: {
      name: fromName,
      email: fromEmail ?? null,
      isCustomer,
    },
    createdAt: ensureString(email.MessageDate) ?? ensureString(email.CreatedDate) ?? nowIsoString(),
    direction: isIncoming ? "inbound" : "outbound",
    hasAttachment: email.HasAttachment === true,
  });
}

/**
 * Transform multiple EmailMessages to CaseMessages.
 */
export function transformEmailMessagesToCaseMessages(
  emails: SalesforceEmailMessage[],
  customerEmail?: string
): CaseMessage[] {
  return emails.map(email => transformEmailMessageToCaseMessage(email, customerEmail));
}

// ============================================================================
// CaseComment Transform Functions
// ============================================================================

/**
 * Build the SOQL SELECT fields for CaseComment queries.
 */
export function buildCaseCommentSelectFields(): string[] {
  return [
    "Id",
    "ParentId",
    "CommentBody",
    "IsPublished",
    "CreatedById",
    "CreatedBy.Id",
    "CreatedBy.Name",
    "CreatedBy.Email",
    "CreatedDate",
  ];
}

/**
 * Build SOQL query for fetching public CaseComments for a Case.
 */
export function buildCaseCommentsForCaseQuery(caseId: string): string {
  const fields = buildCaseCommentSelectFields().join(", ");
  return `
    SELECT ${fields}
    FROM CaseComment
    WHERE ParentId = '${caseId}' AND IsPublished = true
    ORDER BY CreatedDate ASC
  `.trim();
}

/**
 * Transform a Salesforce CaseComment to a unified CaseMessage.
 *
 * @param comment - Raw Salesforce CaseComment
 * @param customerContactId - Customer's Salesforce Contact ID for comparison
 */
export function transformCaseCommentToCaseMessage(
  comment: SalesforceCaseComment,
  customerContactId?: string
): CaseMessage {
  const authorName = comment.CreatedBy?.Name ?? "Unknown";
  const authorEmail = comment.CreatedBy?.Email ?? null;

  // Determine if this is from the customer
  // If CreatedById matches customer's contact ID, it's from customer
  // Otherwise, we assume it's from an agent (conservative approach)
  const isCustomer = customerContactId ? comment.CreatedById === customerContactId : false;

  return caseMessageSchema.parse({
    id: comment.Id,
    type: "comment",
    body: ensureString(comment.CommentBody) ?? "",
    author: {
      name: authorName,
      email: authorEmail,
      isCustomer,
    },
    createdAt: ensureString(comment.CreatedDate) ?? nowIsoString(),
    direction: null, // Comments don't have direction
  });
}

/**
 * Transform multiple CaseComments to CaseMessages.
 */
export function transformCaseCommentsToCaseMessages(
  comments: SalesforceCaseComment[],
  customerContactId?: string
): CaseMessage[] {
  return comments.map(comment => transformCaseCommentToCaseMessage(comment, customerContactId));
}

// ============================================================================
// Unified Message Functions
// ============================================================================

/**
 * Merge and sort EmailMessages and CaseComments into a unified timeline.
 *
 * @param emailMessages - Transformed email messages
 * @param caseComments - Transformed case comments
 * @returns Merged and sorted array of CaseMessages
 */
export function mergeAndSortCaseMessages(
  emailMessages: CaseMessage[],
  caseComments: CaseMessage[]
): CaseMessage[] {
  const allMessages = [...emailMessages, ...caseComments];

  // Sort by createdAt ascending (oldest first)
  return allMessages.sort((a, b) => {
    const dateA = new Date(a.createdAt).getTime();
    const dateB = new Date(b.createdAt).getTime();
    return dateA - dateB;
  });
}
