import type { LogicNode } from './strategyTypes';
import type { StrategyFlowLayoutStore } from './strategyEditorLayoutStorage';
import type { StrategyEditorMode } from './strategyEditorModeStorage';
import type { StrategyDto } from './strategyEditorShared';

export const STRATEGY_EXPORT_VERSION = '1.1';

export interface StrategyExportPayload {
  version: string;
  name?: string;
  description?: string;
  buyCondition?: LogicNode | null;
  sellCondition?: LogicNode | null;
  exportedAt: string;
  source?: 'strategy-builder' | 'strategy-page';
  flowLayout?: StrategyFlowLayoutStore;
  editorMode?: StrategyEditorMode;
}

export interface StrategyListExportItem {
  name: string;
  description?: string;
  buyCondition?: LogicNode | null;
  sellCondition?: LogicNode | null;
  enabled?: boolean;
  flowLayout?: StrategyFlowLayoutStore;
}

export interface StrategyListExportPayload {
  version: string;
  exportedAt: string;
  totalCount: number;
  source?: 'strategy-builder' | 'strategy-page';
  strategies: StrategyListExportItem[];
}

export type StrategyImportResult =
  | { kind: 'single'; data: StrategyExportPayload }
  | { kind: 'list'; data: StrategyListExportPayload };

function isLogicNode(value: unknown): value is LogicNode {
  return !!value && typeof value === 'object' && typeof (value as LogicNode).type === 'string';
}

function hasStrategyConditions(data: Record<string, unknown>): boolean {
  return isLogicNode(data.buyCondition) || isLogicNode(data.sellCondition);
}

export function buildStrategyExportPayload(input: {
  name?: string;
  description?: string;
  buyCondition?: LogicNode | null;
  sellCondition?: LogicNode | null;
  flowLayout?: StrategyFlowLayoutStore;
  editorMode?: StrategyEditorMode;
}): StrategyExportPayload {
  return {
    version: STRATEGY_EXPORT_VERSION,
    source: 'strategy-builder',
    name: input.name,
    description: input.description,
    buyCondition: input.buyCondition ?? null,
    sellCondition: input.sellCondition ?? null,
    flowLayout: input.flowLayout,
    editorMode: input.editorMode,
    exportedAt: new Date().toISOString(),
  };
}

export function buildStrategyListExportPayload(
  strategies: StrategyListExportItem[],
): StrategyListExportPayload {
  return {
    version: STRATEGY_EXPORT_VERSION,
    source: 'strategy-builder',
    exportedAt: new Date().toISOString(),
    totalCount: strategies.length,
    strategies,
  };
}

export function parseStrategyImportFile(text: string): StrategyImportResult {
  let parsed: unknown;
  try {
    parsed = JSON.parse(text);
  } catch {
    throw new Error('JSON 파싱에 실패했습니다');
  }
  if (!parsed || typeof parsed !== 'object') {
    throw new Error('유효하지 않은 JSON 형식입니다');
  }
  const data = parsed as Record<string, unknown>;

  if (Array.isArray(data.strategies)) {
    const strategies = data.strategies.filter((item): item is StrategyListExportItem => {
      if (!item || typeof item !== 'object') return false;
      const row = item as StrategyListExportItem;
      return !!row.name && (isLogicNode(row.buyCondition) || isLogicNode(row.sellCondition));
    });
    if (strategies.length === 0) {
      throw new Error('가져올 전략 조건이 없습니다');
    }
    return {
      kind: 'list',
      data: {
        version: String(data.version ?? STRATEGY_EXPORT_VERSION),
        exportedAt: String(data.exportedAt ?? new Date().toISOString()),
        totalCount: strategies.length,
        source: data.source === 'strategy-page' ? 'strategy-page' : 'strategy-builder',
        strategies,
      },
    };
  }

  if (!hasStrategyConditions(data)) {
    throw new Error('buyCondition 또는 sellCondition이 필요합니다');
  }

  return {
    kind: 'single',
    data: {
      version: String(data.version ?? '1.0'),
      source: data.source === 'strategy-page' ? 'strategy-page' : 'strategy-builder',
      name: typeof data.name === 'string' ? data.name : undefined,
      description: typeof data.description === 'string' ? data.description : undefined,
      buyCondition: isLogicNode(data.buyCondition) ? data.buyCondition : null,
      sellCondition: isLogicNode(data.sellCondition) ? data.sellCondition : null,
      flowLayout: data.flowLayout as StrategyFlowLayoutStore | undefined,
      editorMode: data.editorMode === 'list' || data.editorMode === 'graph'
        ? data.editorMode
        : undefined,
      exportedAt: String(data.exportedAt ?? new Date().toISOString()),
    },
  };
}

export function downloadStrategyJson(filename: string, data: unknown): void {
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
  const href = URL.createObjectURL(blob);
  const anchor = document.createElement('a');
  anchor.href = href;
  anchor.download = filename.endsWith('.json') ? filename : `${filename}.json`;
  document.body.appendChild(anchor);
  anchor.click();
  document.body.removeChild(anchor);
  URL.revokeObjectURL(href);
}

export function pickJsonFile(): Promise<string | null> {
  return new Promise(resolve => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.json,application/json';
    input.onchange = async () => {
      const file = input.files?.[0];
      if (!file) {
        resolve(null);
        return;
      }
      try {
        resolve(await file.text());
      } catch {
        resolve(null);
      }
    };
    input.click();
  });
}

export function strategyDtoToListExportItem(
  strategy: StrategyDto,
  flowLayout?: StrategyFlowLayoutStore | null,
): StrategyListExportItem {
  return {
    name: strategy.name,
    description: strategy.description,
    buyCondition: strategy.buyCondition ?? null,
    sellCondition: strategy.sellCondition ?? null,
    enabled: strategy.enabled,
    flowLayout: flowLayout ?? undefined,
  };
}

export function listImportItemToStrategyDto(item: StrategyListExportItem, id: number): StrategyDto {
  const now = new Date().toISOString();
  return {
    id,
    name: item.name,
    description: item.description,
    buyCondition: item.buyCondition ?? null,
    sellCondition: item.sellCondition ?? null,
    enabled: item.enabled ?? true,
    createdAt: now,
    updatedAt: now,
  };
}
