import 'constants.dart';
import 'chart_engine.dart';
import 'key_analyzer.dart';
import 'models.dart';
/// 跨命局键共振分析 — 比较两造干支之间的键与纠缠
/// © 2026 Jason Li. All rights reserved.

class CrossChartLink {
  final String type;
  final String fromLabel;
  final String toLabel;
  final String detail;
  final double multiplier;

  const CrossChartLink({
    required this.type,
    required this.fromLabel,
    required this.toLabel,
    required this.detail,
    this.multiplier = 2.0,
  });
}

class CrossChartResult {
  final BaziChart chartA;
  final BaziChart chartB;
  final List<CrossChartLink> links;
  final List<String> peerEntanglements;
  final List<String> clashEntanglements;
  final String summary;

  const CrossChartResult({
    required this.chartA,
    required this.chartB,
    required this.links,
    required this.peerEntanglements,
    required this.clashEntanglements,
    required this.summary,
  });
}

class CrossChartAnalyzer {
  static CrossChartResult compare(BirthInput a, BirthInput b) {
    final chartA = ChartEngine.build(a);
    final chartB = ChartEngine.build(b);
    return compareCharts(chartA, chartB);
  }

  static CrossChartResult compareCharts(BaziChart chartA, BaziChart chartB) {
    final links = <CrossChartLink>[];
    final peers = <String>[];
    final clashes = <String>[];

    final stemsA = _labeledStems(chartA);
    final stemsB = _labeledStems(chartB);
    final branchesA = _labeledBranches(chartA);
    final branchesB = _labeledBranches(chartB);

    // 天干五合 / 同字 / 同行 across charts
    for (final sa in stemsA) {
      for (final sb in stemsB) {
        final he = _stemCombine(sa.$2, sb.$2);
        if (he != null) {
          links.add(CrossChartLink(
            type: '天干五合',
            fromLabel: sa.$1,
            toLabel: sb.$1,
            detail: '${sa.$1}${sa.$2} 合 ${sb.$1}${sb.$2} → $he',
            multiplier: 2.0,
          ));
        }
        if (sa.$2 == sb.$2) {
          links.add(CrossChartLink(
            type: '同字共振',
            fromLabel: sa.$1,
            toLabel: sb.$1,
            detail: '天干同字 ${sa.$2}（${sa.$1}↔${sb.$1}）×2',
            multiplier: 2.0,
          ));
        }
        final ea = GanZhi.stemElement[sa.$2]!;
        final eb = GanZhi.stemElement[sb.$2]!;
        if (ea == eb && sa.$2 != sb.$2) {
          peers.add('同行纠缠 $ea：${sa.$1}${sa.$2} ↔ ${sb.$1}${sb.$2}');
          links.add(CrossChartLink(
            type: '同行共振',
            fromLabel: sa.$1,
            toLabel: sb.$1,
            detail: '天干同行$ea ${sa.$2}/${sb.$2}',
            multiplier: 2.0,
          ));
        }
      }
    }

    // 地支关系 across charts
    for (final ba in branchesA) {
      for (final bb in branchesB) {
        final he = _branchSixHe(ba.$2, bb.$2);
        if (he != null) {
          links.add(CrossChartLink(
            type: '地支六合',
            fromLabel: ba.$1,
            toLabel: bb.$1,
            detail: '${ba.$1}${ba.$2} 合 ${bb.$1}${bb.$2} → $he',
            multiplier: 2.0,
          ));
        }
        if (_isPair(branchClashPairs, ba.$2, bb.$2)) {
          clashes.add('对冲纠缠：${ba.$1}${ba.$2} 冲 ${bb.$1}${bb.$2}');
          links.add(CrossChartLink(
            type: '地支六冲',
            fromLabel: ba.$1,
            toLabel: bb.$1,
            detail: '${ba.$1}${ba.$2} 冲 ${bb.$1}${bb.$2}',
            multiplier: 4.0,
          ));
        }
        if (_isPair(branchHarmPairs, ba.$2, bb.$2)) {
          links.add(CrossChartLink(
            type: '地支六害',
            fromLabel: ba.$1,
            toLabel: bb.$1,
            detail: '${ba.$1}${ba.$2} 害 ${bb.$1}${bb.$2}',
          ));
        }
        if (_isPair(branchBreakPairs, ba.$2, bb.$2)) {
          links.add(CrossChartLink(
            type: '地支六破',
            fromLabel: ba.$1,
            toLabel: bb.$1,
            detail: '${ba.$1}${ba.$2} 破 ${bb.$1}${bb.$2}',
          ));
        }
        if (ba.$2 == bb.$2) {
          links.add(CrossChartLink(
            type: '同字共振',
            fromLabel: ba.$1,
            toLabel: bb.$1,
            detail: '地支同字 ${ba.$2}（${ba.$1}↔${bb.$1}）×2',
            multiplier: 2.0,
          ));
        }
      }
    }

    // 半合 / 三合跨局提示
    for (final entry in branchTripleHarmony.entries) {
      final setA = chartA.allBranches.toSet();
      final setB = chartB.allBranches.toSet();
      final needed = entry.value.toSet();
      final union = {...setA, ...setB};
      final hit = needed.intersection(union);
      if (hit.length >= 2 &&
          needed.intersection(setA).isNotEmpty &&
          needed.intersection(setB).isNotEmpty) {
        links.add(CrossChartLink(
          type: '地支三合',
          fromLabel: 'A',
          toLabel: 'B',
          detail:
              '跨局三合${entry.key}：${hit.join("")}${hit.length == 3 ? "（成局）" : "（半合）"}',
          multiplier: hit.length == 3 ? 3.0 : 2.5,
        ));
      }
    }

    final summary = links.isEmpty
        ? '两造之间暂无明显键共振；外部互动偏弱，需流年大运催化。'
        : '检出跨局键 ${links.length} 条；'
            '${peers.isNotEmpty ? "同行纠缠${peers.length}；" : ""}'
            '${clashes.isNotEmpty ? "对冲纠缠${clashes.length}；" : ""}'
            '能量倍数区间 ×${links.map((l) => l.multiplier).reduce((a, b) => a > b ? a : b).toStringAsFixed(1)}。';

    return CrossChartResult(
      chartA: chartA,
      chartB: chartB,
      links: links,
      peerEntanglements: peers,
      clashEntanglements: clashes,
      summary: summary,
    );
  }

  static List<(String, String)> _labeledStems(BaziChart c) {
    const labels = ['年干', '月干', '日干', '时干'];
    return [
      for (var i = 0; i < 4; i++) (labels[i], c.pillars[i].stem),
    ];
  }

  static List<(String, String)> _labeledBranches(BaziChart c) {
    const labels = ['年支', '月支', '日支', '时支'];
    return [
      for (var i = 0; i < 4; i++) (labels[i], c.pillars[i].branch),
    ];
  }

  static String? _stemCombine(String a, String b) {
    for (final e in stemCombinations.entries) {
      if ((e.key.$1 == a && e.key.$2 == b) ||
          (e.key.$1 == b && e.key.$2 == a)) {
        return e.value;
      }
    }
    return null;
  }

  static String? _branchSixHe(String a, String b) {
    for (final e in branchSixHarmony.entries) {
      if ((e.key.$1 == a && e.key.$2 == b) ||
          (e.key.$1 == b && e.key.$2 == a)) {
        return e.value;
      }
    }
    return null;
  }

  static bool _isPair(List<(String, String)> pairs, String a, String b) {
    for (final p in pairs) {
      if ((p.$1 == a && p.$2 == b) || (p.$1 == b && p.$2 == a)) return true;
    }
    return false;
  }
}

/// 流年穿透：流年须与大运或小运成键，方可进入命局
class PenetrationAnalyzer {
  static List<String> analyze({
    required BaziChart chart,
    required int flowYear,
  }) {
    final idx = (flowYear - 1984) % 60;
    final i = idx < 0 ? idx + 60 : idx;
    final gz = GanZhi.sixtyJiaZi[i];
    final flowStem = gz[0];
    final flowBranch = gz[1];

    final hints = <String>[];
    final dy = chart.daYun.isNotEmpty ? chart.daYun.first : null;
    final xy = chart.xiaoYun.isNotEmpty ? chart.xiaoYun.first : null;

    bool linkedTo(Pillar? p) {
      if (p == null) return false;
      if (p.stem == flowStem || p.branch == flowBranch) return true;
      for (final e in stemCombinations.entries) {
        if ((e.key.$1 == flowStem && e.key.$2 == p.stem) ||
            (e.key.$1 == p.stem && e.key.$2 == flowStem)) {
          return true;
        }
      }
      for (final pair in [
        ...branchClashPairs,
        ...branchHarmPairs,
        ...branchBreakPairs,
        ...branchSixHarmony.keys,
      ]) {
        if ((pair.$1 == flowBranch && pair.$2 == p.branch) ||
            (pair.$1 == p.branch && pair.$2 == flowBranch)) {
          return true;
        }
      }
      return false;
    }

    final toDaYun = linkedTo(dy);
    final toXiaoYun = linkedTo(xy);
    hints.add('流年$flowYear $gz');
    if (toDaYun || toXiaoYun) {
      hints.add(
          '穿透：流年与${toDaYun ? "大运${dy!.text}" : ""}${toDaYun && toXiaoYun ? "、" : ""}${toXiaoYun ? "小运${xy!.text}" : ""}成键 → 可进入命局');
    } else {
      hints.add('未穿透：流年与当前大运/小运无键 → 外部噪音，难入命局');
    }

    // Direct natal keys with flow year
    final natalKeys = KeyAnalyzer.identify(chart);
    final touched = natalKeys.where((k) =>
        k.members.contains(flowStem) || k.members.contains(flowBranch));
    if (touched.isNotEmpty) {
      hints.add('与原局相关键：${touched.take(3).map((k) => k.detail).join("；")}');
    }
    return hints;
  }
}
