export type SourceType = "local-file" | "web-url";

export interface SubtitleCue {
  id: string;
  start: number;
  end: number;
  text: string;
}

export interface SubtitleWindow {
  active?: SubtitleCue;
  previous: SubtitleCue[];
  next: SubtitleCue[];
}

export interface WatchRecord {
  id: string;
  title: string;
  sourceType: SourceType;
  sourceLabel: string;
  currentTime: number;
  duration: number;
  updatedAt: string;
  thumbnailDataUrl?: string;
  videoFilePath?: string;
  videoFileName?: string;
  subtitleFileName?: string;
  subtitleFilePath?: string;
  subtitleCount?: number;
  subtitleOffsetSeconds?: number;
  webUrl?: string;
  webOriginalUrl?: string;
  webEmbedUrl?: string;
  webPlatform?: "bilibili";
  webMode?: "embed" | "page";
  companionPlan?: CompanionPlanPoint[];
  companionMode?: string;
  companionDensity?: string;
  triggeredPlanIds?: string[];
}

export interface WatchContext {
  title: string;
  currentTime: number;
  duration: number;
  sourceType: SourceType;
  activeSubtitle?: SubtitleCue;
  subtitleWindow: SubtitleWindow;
  screenshotDataUrl?: string;
}

export interface MemorySnippet {
  id: string;
  title: string;
  text: string;
  score?: number;
  source?: string;
}

export type ModelProvider = "openrouter" | "claude" | "gemini" | "glm" | "deepseek";
export type JournalProvider = "active" | ModelProvider;
export type ThemePreset = "black-gold" | "white-gold" | "pink-mocha" | "custom";
export type FontStylePreset = "system" | "soft";
export type FontSizePreset = "small" | "standard" | "large";
export type MemoryRetrievalMode = "local" | "vector" | "hybrid";
export type VectorProvider = "none" | "local" | "openai" | "gemini";
export type ObsidianScopeMode = "all" | "persona" | "book" | "custom";
export type TimeAwarenessMode = "off" | "date_only" | "realtime";
export type ClaudeCacheTtlMode = "auto" | "5m" | "1h";
export type EmojiFrequency = "off" | "low" | "medium" | "high";

export interface ModelPreset {
  id: string;
  name: string;
}

export interface ProviderProfile {
  apiKey: string;
  baseUrl: string;
  model: string;
  journalModel: string;
}

export interface ContextLoadSettings {
  maxOutputTokens: number;
  shortTermMessageLimit: number;
  memorySnippetLimit: number;
  timeAwarenessMode: TimeAwarenessMode;
  subtitleBefore: number;
  subtitleAfter: number;
  attachScreenshot: boolean;
}

export interface MemoryRetrievalSettings {
  memoryRetrievalMode: MemoryRetrievalMode;
  enableObsidianRetrieval: boolean;
  vectorOnDemandEnabled: boolean;
  vectorOnDemandMinItems: number;
  vectorOnDemandMinChars: number;
  vectorOnDemandPromoteMode: Exclude<MemoryRetrievalMode, "local">;
  vectorProvider: VectorProvider;
  vectorEmbeddingModel: string;
  vectorOpenAIBaseUrl: string;
  vectorOpenAIApiKey: string;
  vectorUseOpenRouterProfile: boolean;
  vectorTopK: number;
  vectorScoreThreshold: number;
  vectorRerank: boolean;
  vectorCrossEncoderRerank: boolean;
  vectorLiteralExactTitleBoost: number;
  vectorLiteralExactAliasBoost: number;
  vectorLiteralExactBodyBoost: number;
  vectorLiteralTermTitleBoost: number;
  vectorLiteralTermBodyBoost: number;
  vectorLiteralBoostCap: number;
  vectorBuildBatchSize: number;
  vectorBuildYieldMs: number;
  rawMemoryDeepDiveEnabled: boolean;
  rawMemoryWindowLimit: number;
  vectorContextBudgetChars: number;
  latestStyleEnabled: boolean;
  latestStyleTopK: number;
  latestStylePathKeyword: string;
  obsidianScopeMode: ObsidianScopeMode;
  obsidianScopeCustom: string;
}

export interface VisualAtmosphereSettings {
  theme: ThemePreset;
  backgroundFit: "cover" | "stage" | "contain";
  customBackgroundDataUrl: string;
  fontStyle: FontStylePreset;
  fontSize: FontSizePreset;
  markdownNarrativeEnabled: boolean;
  emojiFrequency: EmojiFrequency;
  showBilingualLabels: boolean;
  showStatusStrip: boolean;
  showButtonLabels: boolean;
  metaShowName: boolean;
  metaShowTime: boolean;
  metaShowDate: boolean;
  metaShowModel: boolean;
  metaShowTokens: boolean;
}

export interface UplinkSettings {
  activeProvider: ModelProvider;
  journalProvider: JournalProvider;
  claudeCacheTtlMode: ClaudeCacheTtlMode;
  enableReasoning: boolean;
  reasoningPreferChinese: boolean;
  temperature: number;
  stream: boolean;
  profiles: Record<ModelProvider, ProviderProfile>;
  contextLoad: ContextLoadSettings;
  memoryRetrieval: MemoryRetrievalSettings;
  visual: VisualAtmosphereSettings;
}

export interface ConversationTurn {
  role: "user" | "companion";
  text: string;
  attachments?: ConversationAttachment[];
}

export interface PersonaAdapter {
  getPersonaCore(): Promise<string>;
  getUserContext?(): Promise<string>;
}

export interface MemoryAdapter {
  retrieveRelevant(query: string, limit?: number): Promise<MemorySnippet[]>;
}

export interface CompanionRequest {
  mode?: "cinema" | "chat" | "plan" | "watchPrompt";
  channel?: "chat" | "journal";
  purpose?: "topic-recall-judge" | "session-state";
  cacheScope?: string;
  userMessage: string;
  attachments?: ConversationAttachment[];
  watch: WatchContext;
  personaCore: string;
  userContext?: string;
  dynamicContext?: string;
  memories: MemorySnippet[];
  recentMessages?: ConversationTurn[];
  replyAesthetics?: {
    markdownNarrativeEnabled?: boolean;
    emojiFrequency?: EmojiFrequency;
  };
  timeBridgeMeta?: TimeBridgeMeta;
  onStreamUpdate?: (text: string) => void;
  onMetaUpdate?: (meta: { thoughts?: string; thoughtsTranslated?: string }) => void;
  temperatureOverride?: number;
  maxOutputTokensOverride?: number;
  signal?: AbortSignal;
}

export interface TimeBridgeMeta {
  previousUserGapMs?: number;
  recentUserAverageGapMs?: number;
  previousUserMessageAt?: string;
  currentUserMessageAt?: string;
}

export interface CompanionResponse {
  text: string;
  promptPreview?: string;
  modelUsed?: string;
  tokenCount?: number;
  thoughts?: string;
  thoughtsTranslated?: string;
  visionFallbackUsed?: boolean;
}

export interface LLMAdapter {
  complete(request: CompanionRequest): Promise<CompanionResponse>;
}

export interface CompanionAdapters {
  persona: PersonaAdapter;
  memory: MemoryAdapter;
  llm: LLMAdapter;
}

export interface CompanionPlanPoint {
  id: string;
  time: number;
  subtitle?: string;
  companionHint: string;
  type?: "emotion" | "observe" | "question" | "memory";
  priority?: "high" | "medium" | "low";
  delivery?: "auto" | "hint" | "manual";
}

export interface ConversationMessage {
  id: string;
  role: "user" | "companion";
  text: string;
  createdAt: string;
  attachments?: ConversationAttachment[];
  modelUsed?: string;
  tokenCount?: number;
  thoughts?: string;
  thoughtsTranslated?: string;
}

export interface ConversationAttachment {
  id: string;
  type: "image" | "file";
  name: string;
  mimeType: string;
  size: number;
  dataUrl?: string;
  text?: string;
}

export interface ConversationRecord {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
  messages: ConversationMessage[];
  linkedWatchTitle?: string;
  linkedWatchRecordId?: string;
}
