import { getPoiRepository } from '@/data/poi'
import {
  adjustLocalPlan,
  clonePlanResponse,
  cloneTravelPreferences,
  createLocalPlan,
  normalizePlanningRequest,
  normalizeTravelPreferences,
  type PlanningOrigin,
  type PlanningRequest,
  type PlanResponse,
  type TravelPreferences,
  TravelValidationError,
} from '@/domain/travel'
import { loadPlan, loadPlanningRequest, loadPreferences, savePlanningRequest, savePreferences } from './storage'

interface LocalSession {
  plan: PlanResponse
  preferences: TravelPreferences
  request: PlanningRequest
  planningOrigin: PlanningOrigin | null
}

const localSessions = new Map<string, LocalSession>()

function clonePlanningRequest(request: PlanningRequest, includeOrigin = true): PlanningRequest {
  return {
    mode: request.mode,
    preferences: cloneTravelPreferences(request.preferences),
    durationMinutes: request.durationMinutes,
    selectedPoiIds: [...request.selectedPoiIds],
    ...(includeOrigin && request.origin ? { origin: { ...request.origin } } : {}),
  }
}

function rememberLocalSession(plan: PlanResponse, request: PlanningRequest): void {
  const repository = getPoiRepository()
  localSessions.set(plan.conversationId, {
    plan: clonePlanResponse(plan, repository),
    preferences: cloneTravelPreferences(request.preferences),
    request: clonePlanningRequest(request),
    planningOrigin: request.origin ? { ...request.origin } : null,
  })
}

function restoreLocalSession(conversationId: string): LocalSession | null {
  const remembered = localSessions.get(conversationId)
  if (remembered)
    return remembered

  const plan = loadPlan()
  const preferences = loadPreferences()
  if (!plan || !preferences || plan.conversationId !== conversationId)
    return null
  const storedRequest = loadPlanningRequest()
  rememberLocalSession(plan, storedRequest ?? {
    mode: plan.itinerary.planningMode,
    preferences,
    durationMinutes: plan.itinerary.requestedMinutes,
    selectedPoiIds: plan.itinerary.planningMode === 'custom'
      ? plan.itinerary.items.map(item => item.placeId)
      : [],
  })
  return localSessions.get(conversationId) ?? null
}

function normalizePlanningOrigin(origin?: PlanningOrigin): PlanningOrigin | null {
  if (!origin
    || origin.coordinateSystem !== 'GCJ02'
    || !Number.isFinite(origin.longitude)
    || !Number.isFinite(origin.latitude)
    || origin.longitude < -180
    || origin.longitude > 180
    || origin.latitude < -90
    || origin.latitude > 90) {
    return null
  }
  return { ...origin }
}

function isPlanningRequest(input: TravelPreferences | PlanningRequest): input is PlanningRequest {
  return typeof input === 'object' && input !== null && 'mode' in input && 'preferences' in input
}

export function createPlan(input: PlanningRequest): Promise<PlanResponse>
export function createPlan(input: TravelPreferences, planningOrigin?: PlanningOrigin): Promise<PlanResponse>
export async function createPlan(
  input: TravelPreferences | PlanningRequest,
  planningOrigin?: PlanningOrigin,
): Promise<PlanResponse> {
  const repository = getPoiRepository()
  const request = normalizePlanningRequest(isPlanningRequest(input)
    ? input
    : {
        mode: 'quick',
        preferences: normalizeTravelPreferences(input),
        durationMinutes: input.duration === 'half_day' ? 240 : 480,
        selectedPoiIds: [],
        ...(normalizePlanningOrigin(planningOrigin) ? { origin: normalizePlanningOrigin(planningOrigin)! } : {}),
      }, repository)
  const plan = createLocalPlan(request, repository)
  rememberLocalSession(plan, request)
  savePlanningRequest(request)
  return clonePlanResponse(plan, repository)
}

export async function adjustPlan(conversationId: string, message: string): Promise<PlanResponse> {
  const normalizedConversationId = conversationId.trim()
  const normalizedMessage = message.trim()
  if (!normalizedConversationId)
    throw new TravelValidationError('会话 ID 不能为空')
  if (!normalizedMessage)
    throw new TravelValidationError('请填写需要调整的内容')
  if (normalizedMessage.length > 500)
    throw new TravelValidationError('调整内容不能超过 500 字')

  const repository = getPoiRepository()
  const session = restoreLocalSession(normalizedConversationId)
  if (!session)
    throw new Error('本机行程会话不存在，请重新生成行程')
  const adjusted = adjustLocalPlan(
    session.plan,
    session.preferences,
    normalizedMessage,
    repository,
    session.planningOrigin ?? undefined,
    session.request,
  )
  if (session.plan.source !== 'local_poc') {
    adjusted.plan.assistantMessage = '已在本机按你的补充要求重新核算路线；如需 AI 重新选点，请返回规划页重新生成。'
    adjusted.plan.source = 'local_poc'
  }
  rememberLocalSession(adjusted.plan, adjusted.request)
  savePlanningRequest(adjusted.request)
  savePreferences(adjusted.preferences)
  return clonePlanResponse(adjusted.plan, repository)
}

/** Exact planning origins live only in this in-memory session and are never persisted. */
export function getSessionPlanningOrigin(conversationId: string): PlanningOrigin | null {
  const normalizedConversationId = conversationId.trim()
  if (!normalizedConversationId)
    return null
  const origin = localSessions.get(normalizedConversationId)?.planningOrigin
  return origin ? { ...origin } : null
}
