const STORAGE_KEY_PREFIX = 'x-financial:workbench-ai-conversations'
const MAX_CONVERSATION_HISTORY = 30
const MAX_STORED_MESSAGES = 80
const APPLICATION_DETAIL_HREF_PREFIX = '#ai-open-application-detail:'
const DELETED_APPLICATION_DETAIL_HREF_PREFIX = '#ai-deleted-application-detail:'
const DOCUMENT_DETAIL_HREF_PREFIX = '#ai-open-document-detail:'
const DELETED_DOCUMENT_DETAIL_HREF_PREFIX = '#ai-deleted-document-detail:'
const APPLICATION_DETAIL_MARKDOWN_LINK_RE = /\[([^\]]+)\]\((#ai-open-application-detail:[^)]+)\)/g
const DOCUMENT_DETAIL_MARKDOWN_LINK_RE = /\[([^\]]+)\]\((#ai-open-document-detail:[^)]+)\)/g

function safeString(value) {
  return String(value || '').trim()
}

function normalizeIdentifier(value) {
  return safeString(value)
}

function collectDeletedDraftIdentifiers(payload = {}) {
  return new Set([
    payload.claimId,
    payload.claim_id,
    payload.id,
    payload.claimNo,
    payload.claim_no,
    payload.documentNo,
    payload.document_no
  ].map((item) => normalizeIdentifier(item)).filter(Boolean))
}

function decodeDetailHref(href = '', prefix = '') {
  const value = safeString(href)
  if (!value.startsWith(prefix)) {
    return []
  }
  const encodedReference = value.slice(prefix.length)
  if (!encodedReference) {
    return []
  }

  let reference = ''
  try {
    reference = decodeURIComponent(encodedReference).trim()
  } catch {
    reference = encodedReference.trim()
  }

  const identifiers = new Set([reference, encodedReference].map((item) => normalizeIdentifier(item)).filter(Boolean))
  const params = new URLSearchParams(reference)
  const detailParamKeys = ['claim_id', 'claim_no', 'document_no']
  detailParamKeys.forEach((key) => {
    const paramValue = normalizeIdentifier(params.get(key))
    if (paramValue) {
      identifiers.add(paramValue)
    }
  })
  return [...identifiers]
}

function decodeApplicationDetailHref(href = '') {
  return decodeDetailHref(href, APPLICATION_DETAIL_HREF_PREFIX)
}

function decodeDocumentDetailHref(href = '') {
  return decodeDetailHref(href, DOCUMENT_DETAIL_HREF_PREFIX)
}

function applicationDetailHrefMatchesDeletedDraft(href = '', identifiers = new Set()) {
  return decodeApplicationDetailHref(href).some((item) => identifiers.has(item))
}

function documentDetailHrefMatchesDeletedDocument(href = '', identifiers = new Set()) {
  return decodeDocumentDetailHref(href).some((item) => identifiers.has(item))
}

function buildDeletedApplicationDetailHref(href = '') {
  const value = safeString(href)
  if (!value.startsWith(APPLICATION_DETAIL_HREF_PREFIX)) {
    return ''
  }
  return `${DELETED_APPLICATION_DETAIL_HREF_PREFIX}${value.slice(APPLICATION_DETAIL_HREF_PREFIX.length)}`
}

function buildDeletedDocumentDetailHref(href = '') {
  const value = safeString(href)
  if (!value.startsWith(DOCUMENT_DETAIL_HREF_PREFIX)) {
    return ''
  }
  return `${DELETED_DOCUMENT_DETAIL_HREF_PREFIX}${value.slice(DOCUMENT_DETAIL_HREF_PREFIX.length)}`
}

function markApplicationDetailLinksDeleted(content = '', identifiers = new Set()) {
  let changed = false
  const nextContent = String(content || '').replace(APPLICATION_DETAIL_MARKDOWN_LINK_RE, (match, _label, href) => {
    if (!applicationDetailHrefMatchesDeletedDraft(href, identifiers)) {
      return match
    }
    const deletedHref = buildDeletedApplicationDetailHref(href)
    if (!deletedHref) {
      return '草稿已删除'
    }
    changed = true
    return `[草稿已删除](${deletedHref})`
  })
  return { content: nextContent, changed }
}

function markDocumentDetailLinksDeleted(content = '', identifiers = new Set()) {
  let changed = false
  const afterDocumentLinks = String(content || '').replace(DOCUMENT_DETAIL_MARKDOWN_LINK_RE, (match, _label, href) => {
    if (!documentDetailHrefMatchesDeletedDocument(href, identifiers)) {
      return match
    }
    const deletedHref = buildDeletedDocumentDetailHref(href)
    if (!deletedHref) {
      return '单据已删除'
    }
    changed = true
    return `[单据已删除](${deletedHref})`
  })
  const nextContent = afterDocumentLinks.replace(APPLICATION_DETAIL_MARKDOWN_LINK_RE, (match, _label, href) => {
    if (!applicationDetailHrefMatchesDeletedDraft(href, identifiers)) {
      return match
    }
    const deletedHref = buildDeletedApplicationDetailHref(href)
    if (!deletedHref) {
      return '单据已删除'
    }
    changed = true
    return `[单据已删除](${deletedHref})`
  })
  return { content: nextContent, changed }
}

function actionMatchesDeletedDraft(action = {}, identifiers = new Set()) {
  const payload = action?.payload && typeof action.payload === 'object' ? action.payload : {}
  return [
    payload.claim_id,
    payload.claimId,
    payload.id,
    payload.claim_no,
    payload.claimNo,
    payload.document_no,
    payload.documentNo
  ].map((item) => normalizeIdentifier(item)).some((item) => item && identifiers.has(item))
}

function markSuggestedActionsDeleted(actions = [], identifiers = new Set()) {
  let changed = false
  const nextActions = (Array.isArray(actions) ? actions : []).map((action) => {
    const actionType = String(action?.action_type || '').trim()
    if (!['open_application_detail', 'open_document_detail'].includes(actionType)) {
      return action
    }
    if (!actionMatchesDeletedDraft(action, identifiers)) {
      return action
    }
    changed = true
    return {
      ...action,
      label: '草稿已删除',
      description: '草稿单据已经删除，请重新再次申请。',
      icon: 'mdi mdi-trash-can-outline',
      disabled: true,
      action_type: actionType === 'open_document_detail'
        ? 'deleted_document_detail'
        : 'deleted_application_detail'
    }
  })
  return { actions: nextActions, changed }
}

function buildDraftDeletedMessage(payload = {}) {
  const claimNo = safeString(payload.claimNo || payload.claim_no || payload.documentNo || payload.document_no)
  return {
    id: `draft-deleted-${safeString(payload.claimId || payload.claim_id || payload.id || claimNo) || Date.now()}`,
    role: 'assistant',
    content: [
      `用户已经删除了草稿单据${claimNo ? ` ${claimNo}` : ''}。`,
      '草稿单据已经删除，请重新再次申请。'
    ].join('\n\n'),
    feedback: '',
    stewardPlan: null,
    suggestedActions: []
  }
}

function buildDocumentDeletedMessage(payload = {}) {
  const claimNo = safeString(payload.claimNo || payload.claim_no || payload.documentNo || payload.document_no)
  return {
    id: `document-deleted-${safeString(payload.claimId || payload.claim_id || payload.id || claimNo) || Date.now()}`,
    role: 'assistant',
    content: [
      `单据${claimNo ? ` ${claimNo}` : ''} 已经删除或不可访问。`,
      '该历史入口已失效，请返回单据列表重新查询。'
    ].join('\n\n'),
    feedback: '',
    stewardPlan: null,
    suggestedActions: []
  }
}

function conversationHasDeletionNotice(messages = [], identifiers = new Set()) {
  return messages.some((message) => {
    const content = safeString(message?.content)
    return content.includes('用户已经删除了草稿单据') && [...identifiers].some((item) => content.includes(item))
  })
}

function conversationHasDocumentDeletionNotice(messages = [], identifiers = new Set()) {
  return messages.some((message) => {
    const content = safeString(message?.content)
    return content.includes('已经删除或不可访问') && [...identifiers].some((item) => content.includes(item))
  })
}

function resolveUserStorageKey(user = {}) {
  const identity = safeString(user.username || user.email || user.name || 'anonymous')
  return `${STORAGE_KEY_PREFIX}:${identity || 'anonymous'}`
}

function canUseStorage() {
  return typeof window !== 'undefined' && Boolean(window.localStorage)
}

function readStoredList(user = {}) {
  if (!canUseStorage()) {
    return []
  }

  try {
    const payload = JSON.parse(window.localStorage.getItem(resolveUserStorageKey(user)) || '[]')
    return Array.isArray(payload) ? payload : []
  } catch {
    return []
  }
}

function writeStoredList(user = {}, conversations = []) {
  if (!canUseStorage()) {
    return
  }

  const normalized = conversations
    .map((item) => normalizeConversation(item))
    .filter((item) => item.id)
    .sort((left, right) => Number(right.updatedAt || 0) - Number(left.updatedAt || 0))
    .slice(0, MAX_CONVERSATION_HISTORY)

  window.localStorage.setItem(resolveUserStorageKey(user), JSON.stringify(normalized))
}

function normalizeMessage(message = {}) {
  return {
    id: safeString(message.id) || `${Date.now()}-${Math.random().toString(16).slice(2)}`,
    role: safeString(message.role) || 'assistant',
    content: safeString(message.content),
    pending: false,
    feedback: safeString(message.feedback),
    text: safeString(message.text || message.content),
    applicationPreview: message.applicationPreview && typeof message.applicationPreview === 'object'
      ? message.applicationPreview
      : null,
    draftPayload: message.draftPayload && typeof message.draftPayload === 'object'
      ? message.draftPayload
      : null,
    requestedSubmit: Boolean(message.requestedSubmit),
    submitRequiresConfirmation: Boolean(message.submitRequiresConfirmation),
    stewardPlan: message.stewardPlan && typeof message.stewardPlan === 'object'
      ? {
          ...message.stewardPlan,
          streamStatus: safeString(message.stewardPlan.streamStatus) || 'completed'
        }
      : null,
    suggestedActions: Array.isArray(message.suggestedActions) ? message.suggestedActions : [],
    // 保留多 task 推进上下文,刷新后申请预览/报销草稿消息仍能拿到剩余 task 列表。
    stewardRemainingTasks: Array.isArray(message.stewardRemainingTasks) ? message.stewardRemainingTasks : []
  }
}

function normalizeConversation(conversation = {}) {
  const updatedAt = Number(conversation.updatedAt || conversation.updated_at || Date.now())
  const messages = Array.isArray(conversation.messages)
    ? conversation.messages.slice(-MAX_STORED_MESSAGES).map((message) => normalizeMessage(message))
    : []
  const title = safeString(conversation.title) || buildConversationTitle(messages)
  const desc = safeString(conversation.desc || conversation.description) || buildConversationDescription(messages)
  return {
    id: safeString(conversation.id || conversation.conversationId),
    title,
    desc,
    time: formatConversationTime(updatedAt),
    prompt: safeString(conversation.prompt) || resolveFirstUserPrompt(messages),
    source: safeString(conversation.source) || 'workbench',
    sessionType: safeString(conversation.sessionType) || 'steward',
    conversationId: safeString(conversation.conversationId || conversation.id),
    stewardState: conversation.stewardState && typeof conversation.stewardState === 'object'
      ? conversation.stewardState
      : null,
    messages,
    updatedAt
  }
}

function resolveStoredConversationId(conversation = {}) {
  return safeString(conversation.id || conversation.conversationId)
}

function buildConversationTitle(messages = []) {
  const firstUserMessage = messages.find((message) => message.role === 'user' && message.content)
  return safeString(firstUserMessage?.content).slice(0, 18) || '新对话'
}

function buildConversationDescription(messages = []) {
  const lastMessage = [...messages].reverse().find((message) => safeString(message.content))
  return safeString(lastMessage?.content).replace(/\s+/g, ' ').slice(0, 32) || '小财管家对话'
}

function resolveFirstUserPrompt(messages = []) {
  const firstUserMessage = messages.find((message) => message.role === 'user' && message.content)
  return safeString(firstUserMessage?.content)
}

function formatConversationTime(timestamp) {
  const date = new Date(Number(timestamp || Date.now()))
  if (Number.isNaN(date.getTime())) {
    return ''
  }

  const now = new Date()
  const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime()
  const startOfYesterday = startOfToday - 24 * 60 * 60 * 1000
  const timeText = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
  const value = date.getTime()

  if (value >= startOfToday) {
    return `今天 ${timeText}`
  }
  if (value >= startOfYesterday) {
    return '昨天'
  }
  return `${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
}

export function loadAiWorkbenchConversationHistory(user = {}) {
  return readStoredList(user)
    .map((item) => normalizeConversation(item))
    .filter((item) => item.id)
    .sort((left, right) => Number(right.updatedAt || 0) - Number(left.updatedAt || 0))
}

export function saveAiWorkbenchConversation(user = {}, conversation = {}) {
  const normalized = normalizeConversation({
    ...conversation,
    updatedAt: conversation.updatedAt || Date.now()
  })
  if (!normalized.id || !normalized.messages.length) {
    return loadAiWorkbenchConversationHistory(user)
  }

  const nextList = [
    normalized,
    ...readStoredList(user).filter((item) => resolveStoredConversationId(item) !== normalized.id)
  ]
  writeStoredList(user, nextList)
  return loadAiWorkbenchConversationHistory(user)
}

export function deleteAiWorkbenchConversation(user = {}, conversationId = '') {
  const normalizedId = safeString(conversationId)
  const nextList = readStoredList(user).filter((item) => resolveStoredConversationId(item) !== normalizedId)
  writeStoredList(user, nextList)
  return loadAiWorkbenchConversationHistory(user)
}

export function markAiWorkbenchConversationDraftDeleted(user = {}, payload = {}) {
  const identifiers = collectDeletedDraftIdentifiers(payload)
  if (!identifiers.size) {
    return loadAiWorkbenchConversationHistory(user)
  }

  const nextList = readStoredList(user).map((conversation) => {
    const normalized = normalizeConversation(conversation)
    let conversationChanged = false
    const messages = normalized.messages.map((message) => {
      const contentResult = markApplicationDetailLinksDeleted(message.content, identifiers)
      const actionsResult = markSuggestedActionsDeleted(message.suggestedActions, identifiers)
      if (!contentResult.changed && !actionsResult.changed) {
        return message
      }
      conversationChanged = true
      return {
        ...message,
        content: contentResult.content,
        suggestedActions: actionsResult.actions
      }
    })

    if (!conversationChanged) {
      return normalized
    }

    if (!conversationHasDeletionNotice(messages, identifiers)) {
      messages.push(buildDraftDeletedMessage(payload))
    }

    return {
      ...normalized,
      desc: '草稿单据已经删除，请重新再次申请。',
      messages,
      updatedAt: Date.now()
    }
  })

  writeStoredList(user, nextList)
  return loadAiWorkbenchConversationHistory(user)
}

export function markAiWorkbenchConversationDocumentDeleted(user = {}, payload = {}) {
  const identifiers = collectDeletedDraftIdentifiers(payload)
  if (!identifiers.size) {
    return loadAiWorkbenchConversationHistory(user)
  }

  const nextList = readStoredList(user).map((conversation) => {
    const normalized = normalizeConversation(conversation)
    let conversationChanged = false
    const messages = normalized.messages.map((message) => {
      const contentResult = markDocumentDetailLinksDeleted(message.content, identifiers)
      const actionsResult = markSuggestedActionsDeleted(message.suggestedActions, identifiers)
      if (!contentResult.changed && !actionsResult.changed) {
        return message
      }
      conversationChanged = true
      return {
        ...message,
        content: contentResult.content,
        suggestedActions: actionsResult.actions
      }
    })

    if (!conversationChanged) {
      return normalized
    }

    if (!conversationHasDocumentDeletionNotice(messages, identifiers)) {
      messages.push(buildDocumentDeletedMessage(payload))
    }

    return {
      ...normalized,
      desc: '单据已经删除或不可访问。',
      messages,
      updatedAt: Date.now()
    }
  })

  writeStoredList(user, nextList)
  return loadAiWorkbenchConversationHistory(user)
}
