import { ref } from 'vue';

import { useUserStore } from '@easyflow/stores';

import {
  COMPOSER_SHADOW_PREFIX,
  resolveAgentChatIdentity,
} from '#/utils/agent-chat-cache';

import {
  allocateAgentComposerSession,
  deleteAgentComposerDraft,
  getAgentComposerDraft,
  saveAgentComposerDraft,
} from './mediaApi';
import type { AgentComposerDraftPayload, AgentComposerMode } from './mediaApi';
import { useChatImageUploads } from './useChatImageUploads';

const SHADOW_TTL = 24 * 60 * 60 * 1000;

interface ShadowDraft extends AgentComposerDraftPayload {
  pendingSync: boolean;
  shadowExpiresAt: number;
  shadowUpdatedAt: number;
}

export function useAgentComposerDraft(mode: AgentComposerMode) {
  const userStore = useUserStore();
  const agentId = ref('');
  const sessionId = ref('');
  const text = ref('');
  const revision = ref(0);
  const images = useChatImageUploads();
  let saveTimer: ReturnType<typeof setTimeout> | undefined;
  let activation = 0;
  let changeSequence = 0;
  let pendingOperations = 0;
  let operationChain = Promise.resolve();

  function identityScope() {
    return resolveAgentChatIdentity(userStore.userInfo);
  }

  function shadowKey(
    targetAgentId = agentId.value,
    targetSessionId = sessionId.value,
    targetIdentity = identityScope(),
  ) {
    return `${COMPOSER_SHADOW_PREFIX}:${targetIdentity}:${mode}:${targetAgentId}:${targetSessionId}`;
  }

  function activeShadowKey(
    targetAgentId = agentId.value,
    targetIdentity = identityScope(),
  ) {
    return `${COMPOSER_SHADOW_PREFIX}:${targetIdentity}:active:${mode}:${targetAgentId}`;
  }

  function readShadow(targetAgentId: string, preferredSessionId?: string) {
    try {
      if (!identityScope()) return undefined;
      const activeSessionId =
        preferredSessionId ||
        localStorage.getItem(activeShadowKey(targetAgentId)) ||
        '';
      if (!activeSessionId) return undefined;
      const raw = localStorage.getItem(
        shadowKey(targetAgentId, activeSessionId),
      );
      if (!raw) return undefined;
      const draft = JSON.parse(raw) as ShadowDraft;
      if (draft.shadowExpiresAt <= Date.now()) {
        localStorage.removeItem(shadowKey(targetAgentId, activeSessionId));
        return undefined;
      }
      return draft;
    } catch {
      return undefined;
    }
  }

  function writeShadowPayload(
    payload: AgentComposerDraftPayload,
    pendingSync = true,
    serverExpiresAt?: string,
    targetIdentity = identityScope(),
  ) {
    if (!targetIdentity || !payload.agentId || !payload.sessionId) return;
    const parsedServerExpiry = serverExpiresAt
      ? Date.parse(serverExpiresAt)
      : Number.NaN;
    const shadow: ShadowDraft = {
      ...payload,
      pendingSync,
      shadowExpiresAt:
        !pendingSync && Number.isFinite(parsedServerExpiry)
          ? parsedServerExpiry
          : Date.now() + SHADOW_TTL,
      shadowUpdatedAt: Date.now(),
    };
    try {
      localStorage.setItem(
        shadowKey(payload.agentId, payload.sessionId, targetIdentity),
        JSON.stringify(shadow),
      );
      localStorage.setItem(
        activeShadowKey(payload.agentId, targetIdentity),
        payload.sessionId,
      );
    } catch {
      // Redis 仍是权威草稿源，本地存储不足不阻断输入。
    }
  }

  function writeShadow(pendingSync = true, serverExpiresAt?: string) {
    writeShadowPayload(shadowPayload(), pendingSync, serverExpiresAt);
  }

  function clearShadow(
    targetAgentId = agentId.value,
    targetSessionId = sessionId.value,
    targetIdentity = identityScope(),
  ) {
    try {
      if (!targetIdentity) return;
      localStorage.removeItem(
        shadowKey(targetAgentId, targetSessionId, targetIdentity),
      );
      if (
        localStorage.getItem(activeShadowKey(targetAgentId, targetIdentity)) ===
        targetSessionId
      ) {
        localStorage.removeItem(activeShadowKey(targetAgentId, targetIdentity));
      }
    } catch {
      // 忽略不可用的本地存储。
    }
  }

  function payloadOf(): AgentComposerDraftPayload {
    return {
      agentId: agentId.value,
      imageUploadIds: [...images.uploadIds.value],
      mode,
      revision: revision.value,
      sessionId: sessionId.value,
      text: text.value,
    };
  }

  function shadowPayload(): AgentComposerDraftPayload {
    return {
      ...payloadOf(),
      images: images.readyItems.value.map((item) => ({ ...item })),
    };
  }

  function applyDraft(draft: AgentComposerDraftPayload) {
    sessionId.value = String(draft.sessionId);
    text.value = draft.text || '';
    revision.value = Number(draft.revision || 0);
    images.restore(draft.images || []);
    changeSequence++;
  }

  function enqueue(operation: () => Promise<void>) {
    pendingOperations++;
    const queued = operationChain.catch(() => undefined).then(operation);
    operationChain = queued
      .catch(() => undefined)
      .finally(() => {
        pendingOperations--;
      });
    return queued;
  }

  function captureSaveContext() {
    return {
      activation,
      agentId: agentId.value,
      identity: identityScope(),
      sessionId: sessionId.value,
    };
  }

  function isCurrentContext(context: ReturnType<typeof captureSaveContext>) {
    return (
      context.activation === activation &&
      context.agentId === agentId.value &&
      context.identity === identityScope() &&
      (!context.sessionId || context.sessionId === sessionId.value)
    );
  }

  async function ensureSession() {
    if (sessionId.value) return sessionId.value;
    const response = await allocateAgentComposerSession(mode);
    if (response.errorCode !== 0 || !response.data?.sessionId) {
      throw new Error(response.message || '会话创建失败');
    }
    sessionId.value = String(response.data.sessionId);
    return sessionId.value;
  }

  async function activate(targetAgentId: string, preferredSessionId?: string) {
    const switchingScope =
      Boolean(agentId.value && sessionId.value) &&
      (targetAgentId !== agentId.value ||
        Boolean(preferredSessionId && preferredSessionId !== sessionId.value));
    if (
      switchingScope &&
      (Boolean(saveTimer) ||
        pendingOperations > 0 ||
        Boolean(text.value.trim()) ||
        images.uploadIds.value.length > 0)
    ) {
      await flush();
    }
    const currentActivation = ++activation;
    if (saveTimer) {
      clearTimeout(saveTimer);
      saveTimer = undefined;
    }
    agentId.value = targetAgentId;
    sessionId.value = preferredSessionId || '';
    text.value = '';
    revision.value = 0;
    images.clear();
    if (!targetAgentId) return;
    const shadow = readShadow(targetAgentId, preferredSessionId);
    try {
      const response = await getAgentComposerDraft({
        agentId: targetAgentId,
        mode,
        ...(preferredSessionId ? { sessionId: preferredSessionId } : {}),
      });
      if (currentActivation !== activation) return;
      if (response.errorCode !== 0) {
        throw new Error(response.message || '聊天草稿读取失败');
      }
      if (shadow?.pendingSync) {
        shadow.revision = Number(response.data?.revision || 0);
        applyDraft(shadow);
        await save();
        return;
      }
      if (response.data) {
        applyDraft(response.data);
        writeShadow(false, response.data.expiresAt);
        return;
      }
      if (shadow) {
        applyDraft(shadow);
        await save();
        return;
      }
      await ensureSession();
    } catch (error) {
      if (currentActivation !== activation) return;
      if (shadow) {
        applyDraft(shadow);
        return;
      }
      await ensureSession();
      throw error;
    }
  }

  async function performSave(context: ReturnType<typeof captureSaveContext>) {
    if (!context.agentId || !context.identity || !isCurrentContext(context)) {
      return;
    }
    await ensureSession();
    if (!isCurrentContext(context)) {
      return;
    }
    const request = shadowPayload();
    const savedSequence = changeSequence;
    if (!request.text.trim() && request.imageUploadIds.length === 0) {
      clearShadow(request.agentId, request.sessionId, context.identity);
      const response = await deleteAgentComposerDraft({
        agentId: request.agentId,
        deleteUploads: true,
        mode,
        sessionId: request.sessionId,
      });
      if (response.errorCode !== 0) {
        throw new Error(response.message || '聊天草稿删除失败');
      }
      if (isCurrentContext(context)) {
        revision.value = 0;
      }
      return;
    }
    writeShadowPayload(request, true, undefined, context.identity);
    const response = await saveAgentComposerDraft(request);
    if (response.errorCode !== 0 || !response.data) {
      throw new Error(response.message || '聊天草稿保存失败');
    }
    if (!isCurrentContext(context)) {
      return;
    }
    revision.value = Number(response.data.revision || revision.value);
    writeShadow(changeSequence !== savedSequence, response.data.expiresAt);
  }

  function save() {
    const context = captureSaveContext();
    return enqueue(() => performSave(context));
  }

  function scheduleSave() {
    changeSequence++;
    writeShadow();
    if (saveTimer) clearTimeout(saveTimer);
    saveTimer = setTimeout(() => {
      saveTimer = undefined;
      void save().catch(() => undefined);
    }, 500);
  }

  async function flush() {
    if (saveTimer) {
      clearTimeout(saveTimer);
      saveTimer = undefined;
    }
    await save();
  }

  async function clear(deleteRemote = true, deleteUploads = true) {
    if (saveTimer) {
      clearTimeout(saveTimer);
      saveTimer = undefined;
    }
    const scope = {
      identity: identityScope(),
      agentId: agentId.value,
      imageUploadIds: [...images.uploadIds.value],
      mode,
      sessionId: sessionId.value,
    };
    activation++;
    changeSequence++;
    clearShadow(scope.agentId, scope.sessionId, scope.identity);
    text.value = '';
    revision.value = 0;
    images.clear();
    if (deleteRemote && scope.agentId && scope.sessionId) {
      await enqueue(async () => {
        const response = await deleteAgentComposerDraft({
          agentId: scope.agentId,
          deleteUploads,
          imageUploadIds: scope.imageUploadIds,
          mode: scope.mode,
          sessionId: scope.sessionId,
        });
        if (response.errorCode !== 0) {
          throw new Error(response.message || '聊天草稿删除失败');
        }
        clearShadow(scope.agentId, scope.sessionId, scope.identity);
      });
    }
  }

  async function markAccepted() {
    await clear(true, mode === 'FORMAL');
  }

  async function startNew(targetAgentId: string) {
    if (
      agentId.value &&
      sessionId.value &&
      (saveTimer ||
        pendingOperations > 0 ||
        text.value.trim() ||
        images.uploadIds.value.length > 0)
    ) {
      await flush();
      text.value = '';
      images.clear();
    }
    const response = await allocateAgentComposerSession(mode);
    if (response.errorCode !== 0 || !response.data?.sessionId) {
      throw new Error(response.message || '会话创建失败');
    }
    await activate(targetAgentId, String(response.data.sessionId));
  }

  return {
    activate,
    agentId,
    clear,
    ensureSession,
    flush,
    images,
    markAccepted,
    revision,
    scheduleSave,
    sessionId,
    startNew,
    text,
  };
}
