import 'divination_params.dart'; class DivinationResultData { const DivinationResultData({ this.threadId, required this.params, required this.binaryCode, required this.changedBinaryCode, required this.guaName, required this.targetGuaName, required this.upperName, required this.lowerName, required this.signType, required this.keywords, required this.focusPoints, required this.conclusion, required this.analysis, required this.suggestion, required this.ganzhi, required this.wuXingStatus, required this.yaoLines, required this.targetYaoLines, }); final DivinationParams params; final String? threadId; final String binaryCode; final String changedBinaryCode; final String guaName; final String targetGuaName; final String upperName; final String lowerName; final String signType; final String keywords; final List focusPoints; final String conclusion; final String analysis; final String suggestion; final GanzhiData ganzhi; final Map wuXingStatus; final List yaoLines; final List targetYaoLines; bool get hasChangingYao => binaryCode != changedBinaryCode; Map toJson() { return { 'params': params.toPayload(), 'threadId': threadId, 'binaryCode': binaryCode, 'changedBinaryCode': changedBinaryCode, 'guaName': guaName, 'targetGuaName': targetGuaName, 'upperName': upperName, 'lowerName': lowerName, 'signType': signType, 'keywords': keywords, 'focusPoints': focusPoints, 'conclusion': conclusion, 'analysis': analysis, 'suggestion': suggestion, 'ganzhi': ganzhi.toJson(), 'wuXingStatus': wuXingStatus, 'yaoLines': yaoLines.map((line) => line.toJson()).toList(growable: false), 'targetYaoLines': targetYaoLines .map((line) => line.toJson()) .toList(growable: false), }; } factory DivinationResultData.fromJson(Map json) { final paramsRaw = json['params']; final ganzhiRaw = json['ganzhi']; final wuXingRaw = json['wuXingStatus']; final yaoLinesRaw = json['yaoLines']; final targetYaoLinesRaw = json['targetYaoLines']; if (paramsRaw is! Map || ganzhiRaw is! Map || wuXingRaw is! Map || yaoLinesRaw is! List || targetYaoLinesRaw is! List) { throw const FormatException('Invalid divination result payload'); } return DivinationResultData( params: DivinationParams.fromPayload(paramsRaw), threadId: json['threadId'] as String?, binaryCode: _requiredString(json, 'binaryCode'), changedBinaryCode: _requiredString(json, 'changedBinaryCode'), guaName: _requiredString(json, 'guaName'), targetGuaName: _requiredString(json, 'targetGuaName'), upperName: _requiredString(json, 'upperName'), lowerName: _requiredString(json, 'lowerName'), signType: _requiredString(json, 'signType'), keywords: _requiredString(json, 'keywords'), focusPoints: _requiredStringList(json, 'focusPoints'), conclusion: _requiredString(json, 'conclusion'), analysis: _requiredString(json, 'analysis'), suggestion: _requiredString(json, 'suggestion'), ganzhi: GanzhiData.fromJson(ganzhiRaw), wuXingStatus: wuXingRaw.map( (key, value) => MapEntry(key, value.toString()), ), yaoLines: yaoLinesRaw .map((raw) { if (raw is! Map) { throw const FormatException('Invalid yao line payload'); } return YaoLineData.fromJson(raw); }) .toList(growable: false), targetYaoLines: targetYaoLinesRaw .map((raw) { if (raw is! Map) { throw const FormatException('Invalid target yao line payload'); } return YaoLineData.fromJson(raw); }) .toList(growable: false), ); } } List _requiredStringList(Map json, String key) { final raw = json[key]; if (raw is! List) { throw FormatException('Invalid $key payload'); } return raw .map((item) { if (item is! String) { throw FormatException('Invalid $key item payload'); } return item; }) .toList(growable: false); } class GanzhiData { const GanzhiData({ required this.yearGanZhi, required this.monthGanZhi, required this.dayGanZhi, required this.timeGanZhi, required this.yearKongWang, required this.monthKongWang, required this.dayKongWang, required this.timeKongWang, required this.yueJian, required this.riChen, required this.yuePo, required this.riChong, }); final String yearGanZhi; final String monthGanZhi; final String dayGanZhi; final String timeGanZhi; final String yearKongWang; final String monthKongWang; final String dayKongWang; final String timeKongWang; final String yueJian; final String riChen; final String yuePo; final String riChong; Map toJson() { return { 'yearGanZhi': yearGanZhi, 'monthGanZhi': monthGanZhi, 'dayGanZhi': dayGanZhi, 'timeGanZhi': timeGanZhi, 'yearKongWang': yearKongWang, 'monthKongWang': monthKongWang, 'dayKongWang': dayKongWang, 'timeKongWang': timeKongWang, 'yueJian': yueJian, 'riChen': riChen, 'yuePo': yuePo, 'riChong': riChong, }; } factory GanzhiData.fromJson(Map json) { return GanzhiData( yearGanZhi: _requiredString(json, 'yearGanZhi'), monthGanZhi: _requiredString(json, 'monthGanZhi'), dayGanZhi: _requiredString(json, 'dayGanZhi'), timeGanZhi: _requiredString(json, 'timeGanZhi'), yearKongWang: _requiredString(json, 'yearKongWang'), monthKongWang: _requiredString(json, 'monthKongWang'), dayKongWang: _requiredString(json, 'dayKongWang'), timeKongWang: _requiredString(json, 'timeKongWang'), yueJian: _requiredString(json, 'yueJian'), riChen: _requiredString(json, 'riChen'), yuePo: _requiredString(json, 'yuePo'), riChong: _requiredString(json, 'riChong'), ); } } class YaoLineData { const YaoLineData({ required this.index, required this.spirit, required this.relation, required this.branch, required this.element, required this.type, required this.mark, }); final int index; final String spirit; final String relation; final String branch; final String element; final YaoType type; final String mark; Map toJson() { return { 'index': index, 'spirit': spirit, 'relation': relation, 'branch': branch, 'element': element, 'type': type.name, 'mark': mark, }; } factory YaoLineData.fromJson(Map json) { return YaoLineData( index: _requiredInt(json, 'index'), spirit: _requiredString(json, 'spirit'), relation: _requiredString(json, 'relation'), branch: _requiredString(json, 'branch'), element: _requiredString(json, 'element'), type: yaoTypeFromName(_requiredString(json, 'type')), mark: _requiredString(json, 'mark'), ); } } String _requiredString(Map json, String key) { final value = json[key]; if (value is! String || value.isEmpty) { throw FormatException('Missing required string: $key'); } return value; } int _requiredInt(Map json, String key) { final value = json[key]; if (value is int) { return value; } if (value is num) { return value.toInt(); } throw FormatException('Missing required int: $key'); }