/**
 * Portal ticket attachment key validation — tenant-portals (wave 9d).
 * Reuses the staff ticket_message MIME allowlist from unified-attachments.
 */
import type { AppEnv } from '../types'
import { createSignedDownloadUrl } from './portal-file-storage'

/** Staff ticket_message allowlist — reused for portal ticket attachment uploads. */
export const PORTAL_TICKET_ATTACHMENT_ALLOWED_MIME = new Set([
  'image/jpeg',
  'image/png',
  'image/gif',
  'image/webp',
  'image/bmp',
  'image/tiff',
  'application/pdf',
  'text/plain',
  'text/csv',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'application/vnd.ms-excel',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'application/zip',
  'video/mp4',
  'video/quicktime',
])

export const MAX_PORTAL_TICKET_ATTACHMENT_BYTES = 25 * 1024 * 1024

export class PortalTicketAttachmentValidationError extends Error {
  constructor(
    public readonly code: string,
    message: string,
  ) {
    super(message)
    this.name = 'PortalTicketAttachmentValidationError'
  }
}

export function validatePortalTicketAttachmentUpload(input: {
  mime_type: string
  file_size_bytes: number
}): void {
  if (!input.mime_type?.trim()) {
    throw new PortalTicketAttachmentValidationError('INVALID_MIME_TYPE', 'mime_type is required')
  }
  const mime = input.mime_type.split(';')[0]!.trim().toLowerCase()
  if (!PORTAL_TICKET_ATTACHMENT_ALLOWED_MIME.has(mime)) {
    throw new PortalTicketAttachmentValidationError('MIME_NOT_ALLOWED', `File type not permitted: ${mime}`)
  }
  if (input.file_size_bytes > MAX_PORTAL_TICKET_ATTACHMENT_BYTES) {
    throw new PortalTicketAttachmentValidationError(
      'FILE_TOO_LARGE',
      `File size ${input.file_size_bytes} exceeds maximum ${MAX_PORTAL_TICKET_ATTACHMENT_BYTES} bytes`,
    )
  }
}

export interface ParsedPortalTicketAttachment {
  r2Key: string
  filename: string
  mimeType: string
  sizeBytes: number
  url: string
}

export function isValidPortalTicketAttachmentKey(
  tenantId: string,
  customerId: string,
  key: string,
): boolean {
  const ticketPrefix = `${tenantId}/ticket_message/`
  const portalPrefix = `${tenantId}/portal/${customerId}/`
  return key.startsWith(ticketPrefix) || key.startsWith(portalPrefix)
}

function filenameFromKey(key: string): string {
  const segment = key.split('/').pop() ?? 'file'
  const dash = segment.indexOf('-')
  return dash >= 0 ? segment.slice(dash + 1) : segment
}

export async function resolvePortalTicketAttachments(
  env: AppEnv['Bindings'],
  tenantId: string,
  customerId: string,
  keys: string[] | undefined,
): Promise<ParsedPortalTicketAttachment[]> {
  if (!keys?.length) return []

  const storage = env.STORAGE
  if (!storage) {
    throw new Error('STORAGE binding unavailable')
  }

  const resolved: ParsedPortalTicketAttachment[] = []
  for (const key of keys) {
    if (!isValidPortalTicketAttachmentKey(tenantId, customerId, key)) {
      throw new Error(`Invalid attachment key: ${key}`)
    }

    const head = await storage.head(key)
    if (!head) {
      throw new Error(`Attachment not found: ${key}`)
    }

    const mimeType = (head.httpMetadata?.contentType ?? 'application/octet-stream')
      .split(';')[0]!
      .trim()
      .toLowerCase()

    if (!PORTAL_TICKET_ATTACHMENT_ALLOWED_MIME.has(mimeType)) {
      throw new Error(`Disallowed attachment type: ${mimeType}`)
    }

    const filename = filenameFromKey(key)
    const url = await createSignedDownloadUrl(env, key, { filename })
    resolved.push({
      r2Key: key,
      filename,
      mimeType,
      sizeBytes: head.size,
      url,
    })
  }

  return resolved
}
