import { Solar } from "lunar-javascript"; import { adjustToTrueSolarTime, formatDateTime, parseDateTime, } from "@/lib/calc/time"; export interface BaziInput { date: string; time: string; gender: "male" | "female"; longitude: number; unknownHour?: boolean; } export interface PillarInfo { ganZhi: string; shiShenGan: string; shiShenZhi: string[]; hideGan: string[]; naYin: string; } export interface DaYunInfo { ganZhi: string; startAge: number; } export interface BaziChart { birthTime: string; trueSolarTime: string; unknownHour: boolean; lunarDate: string; pillars: { year: PillarInfo; month: PillarInfo; day: PillarInfo; time: PillarInfo; }; daYun: { startYear: number; startMonth: number; startDay: number; items: DaYunInfo[]; }; liuNian: { year: number; ganZhi: string }[]; shenSha: { ji: string[]; xiong: string[]; }; } function buildPillar( ganZhi: string, shiShenGan: string, shiShenZhi: string[], hideGan: string[], naYin: string, ): PillarInfo { return { ganZhi, shiShenGan, shiShenZhi, hideGan, naYin }; } export function calculateBazi(input: BaziInput): BaziChart { const localTime = parseDateTime(input.date, input.time); const trueSolar = adjustToTrueSolarTime(localTime, input.longitude); const solar = Solar.fromYmdHms( trueSolar.getFullYear(), trueSolar.getMonth() + 1, trueSolar.getDate(), input.unknownHour ? 12 : trueSolar.getHours(), input.unknownHour ? 0 : trueSolar.getMinutes(), 0, ); const lunar = solar.getLunar(); const ec = lunar.getEightChar(); const genderCode = input.gender === "male" ? 1 : 0; const yun = ec.getYun(genderCode); const currentYear = new Date().getFullYear(); const liuNian: { year: number; ganZhi: string }[] = []; for (let year = currentYear - 2; year <= currentYear + 3; year++) { const yearSolar = Solar.fromYmdHms(year, 6, 1, 12, 0, 0); liuNian.push({ year, ganZhi: yearSolar.getLunar().getYearInGanZhi(), }); } const daYunList = yun.getDaYun(); const daYunItems: DaYunInfo[] = []; let age = yun.getStartYear(); for (const dy of daYunList) { const gz = dy.getGanZhi(); if (!gz) { continue; } daYunItems.push({ ganZhi: gz, startAge: age }); age += 10; if (daYunItems.length >= 8) { break; } } return { birthTime: formatDateTime(localTime), trueSolarTime: formatDateTime(trueSolar), unknownHour: !!input.unknownHour, lunarDate: lunar.toString(), pillars: { year: buildPillar( ec.getYear(), ec.getYearShiShenGan(), ec.getYearShiShenZhi(), ec.getYearHideGan(), ec.getYearNaYin(), ), month: buildPillar( ec.getMonth(), ec.getMonthShiShenGan(), ec.getMonthShiShenZhi(), ec.getMonthHideGan(), ec.getMonthNaYin(), ), day: buildPillar( ec.getDay(), ec.getDayShiShenGan(), ec.getDayShiShenZhi(), ec.getDayHideGan(), ec.getDayNaYin(), ), time: buildPillar( input.unknownHour ? "不详" : ec.getTime(), input.unknownHour ? "—" : ec.getTimeShiShenGan(), input.unknownHour ? [] : ec.getTimeShiShenZhi(), input.unknownHour ? [] : ec.getTimeHideGan(), input.unknownHour ? "—" : ec.getTimeNaYin(), ), }, daYun: { startYear: yun.getStartYear(), startMonth: yun.getStartMonth(), startDay: yun.getStartDay(), items: daYunItems, }, liuNian, shenSha: { ji: lunar.getDayJiShen(), xiong: lunar.getDayXiongSha(), }, }; } export function formatBaziForPrompt(chart: BaziChart): string { const p = chart.pillars; const lines = [ `出生时间:${chart.birthTime}`, `真太阳时:${chart.trueSolarTime}${chart.unknownHour ? "(时辰不详,按中午排盘)" : ""}`, `农历:${chart.lunarDate}`, "", "【四柱】", `年柱:${p.year.ganZhi}(天干十神:${p.year.shiShenGan},地支十神:${p.year.shiShenZhi.join("、")},藏干:${p.year.hideGan.join("、")},纳音:${p.year.naYin})`, `月柱:${p.month.ganZhi}(天干十神:${p.month.shiShenGan},地支十神:${p.month.shiShenZhi.join("、")},藏干:${p.month.hideGan.join("、")},纳音:${p.month.naYin})`, `日柱:${p.day.ganZhi}(天干十神:${p.day.shiShenGan},地支十神:${p.day.shiShenZhi.join("、")},藏干:${p.day.hideGan.join("、")},纳音:${p.day.naYin})`, `时柱:${p.time.ganZhi}(天干十神:${p.time.shiShenGan},地支十神:${p.time.shiShenZhi.join("、") || "—"},藏干:${p.time.hideGan.join("、") || "—"},纳音:${p.time.naYin})`, "", `【大运】起运 ${chart.daYun.startYear} 年 ${chart.daYun.startMonth} 月 ${chart.daYun.startDay} 天`, chart.daYun.items.map((d) => `${d.startAge}岁起 ${d.ganZhi}`).join(" → "), "", `【流年】${chart.liuNian.map((l) => `${l.year}(${l.ganZhi})`).join("、")}`, "", `【神煞】吉神:${chart.shenSha.ji.join("、") || "无"};凶煞:${chart.shenSha.xiong.join("、") || "无"}`, ]; return lines.join("\n"); }