/// Domain models for Key Resonance Destiny Analysis
/// © 2026 Jason Li. All rights reserved.
enum Gender { male, female }

class BirthInput {
  final String name;
  final DateTime localDateTime;
  final double longitude;
  final double latitude;
  final Gender gender;
  final String placeName;

  const BirthInput({
    required this.name,
    required this.localDateTime,
    required this.longitude,
    required this.latitude,
    required this.gender,
    this.placeName = '',
  });

  bool get isSouthernHemisphere => latitude < 0;
}

class TimeCorrectionResult {
  final DateTime beijingTime;
  final int dayPillarOffset;
  final bool crossedDateLine;
  final bool southernHemisphere;
  final Duration longitudeOffset;

  const TimeCorrectionResult({
    required this.beijingTime,
    required this.dayPillarOffset,
    required this.crossedDateLine,
    required this.southernHemisphere,
    required this.longitudeOffset,
  });
}

class Pillar {
  final String stem;
  final String branch;
  final String label;

  const Pillar({required this.stem, required this.branch, this.label = ''});

  String get text => '$stem$branch';

  @override
  String toString() => text;
}

class BaziChart {
  final Pillar year;
  final Pillar month;
  final Pillar day;
  final Pillar hour;
  final TimeCorrectionResult correction;
  final List<Pillar> daYun;
  final List<Pillar> xiaoYun;
  final Gender gender;
  final BirthInput input;

  const BaziChart({
    required this.year,
    required this.month,
    required this.day,
    required this.hour,
    required this.correction,
    required this.daYun,
    required this.xiaoYun,
    required this.gender,
    required this.input,
  });

  String get dayMaster => day.stem;

  List<Pillar> get pillars => [year, month, day, hour];

  List<String> get allStems => pillars.map((p) => p.stem).toList();

  List<String> get allBranches => pillars.map((p) => p.branch).toList();

  String get fourPillarsText =>
      '${year.text} ${month.text} ${day.text} ${hour.text}';
}

class KeyRelation {
  final String type;
  final List<String> members;
  final String? transformedElement;
  final String detail;
  final double baseMultiplier;

  const KeyRelation({
    required this.type,
    required this.members,
    this.transformedElement,
    this.detail = '',
    this.baseMultiplier = 1.0,
  });

  @override
  String toString() =>
      '$type: ${members.join("")}${transformedElement != null ? "→$transformedElement" : ""}';
}

class ResonanceResult {
  final List<KeyRelation> resonanceKeys;
  final List<KeyRelation> entanglementKeys;
  final Map<String, double> multipliers;

  const ResonanceResult({
    required this.resonanceKeys,
    required this.entanglementKeys,
    required this.multipliers,
  });
}

class EnergyProfile {
  final Map<String, double> elementEnergy;
  final String seasonalElement;
  final List<String> roots;
  final List<String> openVaults;
  final Map<String, double> stemEnergy;

  const EnergyProfile({
    required this.elementEnergy,
    required this.seasonalElement,
    required this.roots,
    required this.openVaults,
    required this.stemEnergy,
  });
}

class LiuQinEntry {
  final String relation;
  final String stem;
  final String tenGod;
  final String source; // 原局天干 / 藏干 / 无星看宫 / 大运
  final String layer; // 家内第一层 / 家内第二层 / 家外第三层
  final String? palace;

  const LiuQinEntry({
    required this.relation,
    required this.stem,
    required this.tenGod,
    required this.source,
    required this.layer,
    this.palace,
  });
}

class JudgmentReport {
  final BaziChart chart;
  final List<KeyRelation> keys;
  final ResonanceResult resonance;
  final EnergyProfile energy;
  final List<LiuQinEntry> liuQin;
  final String structureType;
  final List<String> coreKeys;
  final String digestion;
  final List<String> timingHints;
  final Map<String, String> functionTranslation;
  final String rawText;
  final double accuracyCap;

  const JudgmentReport({
    required this.chart,
    required this.keys,
    required this.resonance,
    required this.energy,
    required this.liuQin,
    required this.structureType,
    required this.coreKeys,
    required this.digestion,
    required this.timingHints,
    required this.functionTranslation,
    required this.rawText,
    this.accuracyCap = 0.80,
  });
}
