import unittest
import sys
import os

# Add the parent directory to the Python path so we can import the module
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from iching.utils.bzshagod import find_tian_yi
from iching.utils import bzshagod

class TianYiTests(unittest.TestCase):
    def test_find_tian_yi_basic(self):
        """Test basic 天乙贵人 calculation with a simple case"""
        # 日干甲 with 丑 and 未 in different pillars
        bazi_data = {
            'year': {'g': 0, 'e': 1},  # 甲丑 - should find 阴贵人
            'month': {'g': 1, 'e': 7},  # 乙未 - should find 阳贵人
            'day': {'g': 0, 'e': 2},    # 甲寅 - no 贵人
            'hour': {'g': 2, 'e': 3}     # 丙卯 - no 贵人
        }
        
        results = find_tian_yi(bazi_data)
        self.assertEqual(len(results), 2)
        
        # Check year pillar (丑)
        self.assertEqual(results[0], ('year', 1, 0))  # 0 indicates 阴贵人
        
        # Check month pillar (未)
        self.assertEqual(results[1], ('month', 7, 1))  # 1 indicates 阳贵人

    def test_find_tian_yi_no_matches(self):
        """Test when no 天乙贵人 is present"""
        bazi_data = {
            'year': {'g': 0, 'e': 2},  # 甲寅
            'month': {'g': 1, 'e': 3},  # 乙卯
            'day': {'g': 0, 'e': 4},    # 甲辰
            'hour': {'g': 2, 'e': 5}     # 丙巳
        }
        
        results = find_tian_yi(bazi_data)
        self.assertEqual(len(results), 0)

    def test_find_tian_yi_multiple_matches(self):
        """Test when multiple 天乙贵人 are present"""
        # 日干戊 with 丑 and 未 in different pillars
        bazi_data = {
            'year': {'g': 0, 'e': 1},  # 甲丑
            'month': {'g': 1, 'e': 7},  # 乙未
            'day': {'g': 4, 'e': 2},    # 戊寅
            'hour': {'g': 2, 'e': 1}     # 丙丑
        }
        
        results = find_tian_yi(bazi_data)
        
        # For 日干戊, 丑 is 阳贵人 and 未 is 阴贵人
        found_branches = [(r[1], r[2]) for r in results]
        self.assertIn((1, 1), found_branches)  # 丑 with 阳贵人
        self.assertIn((7, 0), found_branches)  # 未 with 阴贵人

    def test_find_tian_yi_missing_hour(self):
        """Test when hour pillar is not provided"""
        bazi_data = {
            'year': {'g': 0, 'e': 1},  # 甲丑
            'month': {'g': 1, 'e': 7},  # 乙未
            'day': {'g': 4, 'e': 2},    # 戊寅
        }
        
        results = find_tian_yi(bazi_data)
        self.assertEqual(len(results), 2)

    def test_all_cases(self):
        """Test that all day stems can find their 天乙贵人"""
        bazi_data = {
            'year': {'g': 0, 'e': 1},   # 甲丑
            'month': {'g': 1, 'e': 7},   # 乙未
            'day': {'g': 0, 'e': 2},  # 甲
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 1, 0))  # 0 indicates 阴贵人
        self.assertEqual(results[1], ('month', 7, 1))  # 1 indicates 阳贵人

        bazi_data = {
            'year': {'g': 0, 'e': 8},   # 申
            'month': {'g': 1, 'e': 0},   # 子
            'day': {'g': 1, 'e': 2},  # 乙
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 8, 1))
        self.assertEqual(results[1], ('month', 0, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 9},   # 酉
            'month': {'g': 1, 'e': 11},   # 亥
            'day': {'g': 2, 'e': 2},  # 丙
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 9, 1))
        self.assertEqual(results[1], ('month', 11, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 11},   # 亥
            'month': {'g': 1, 'e': 9},   # 酉
            'day': {'g': 3, 'e': 2},  # 丁
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 11, 1))
        self.assertEqual(results[1], ('month', 9, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 1},   # 丑
            'month': {'g': 1, 'e': 7},   # 未
            'day': {'g': 4, 'e': 2},  # 戊
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 1, 1))
        self.assertEqual(results[1], ('month', 7, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 0},   # 子
            'month': {'g': 1, 'e': 8},   # 申
            'day': {'g': 5, 'e': 2},  # 己
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 0, 1))
        self.assertEqual(results[1], ('month', 8, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 1},   # 丑
            'month': {'g': 1, 'e': 7},   # 未
            'day': {'g': 6, 'e': 2},  # 庚
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 1, 1))
        self.assertEqual(results[1], ('month', 7, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 2},   # 寅
            'month': {'g': 1, 'e': 6},   # 午
            'day': {'g': 7, 'e': 2},  # 辛
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 2, 1))
        self.assertEqual(results[1], ('month', 6, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 3},   # 卯
            'month': {'g': 1, 'e': 5},   # 巳
            'day': {'g': 8, 'e': 2},  # 壬
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 3, 1))
        self.assertEqual(results[1], ('month', 5, 0))

        bazi_data = {
            'year': {'g': 0, 'e': 5},   # 巳
            'month': {'g': 1, 'e': 3},   # 卯
            'day': {'g': 9, 'e': 2},  # 癸
            'hour': {'g': 2, 'e': 3}     # 丙卯
        }
        results = find_tian_yi(bazi_data)
        self.assertEqual(results[0], ('year', 5, 1))
        self.assertEqual(results[1], ('month', 3, 0))

class TianDeTests(unittest.TestCase):

    def test_all_cases(self):
        """Test that all month earth branches for 天德贵人"""
        bazi_data = {
            'year': {'g': 0, 'e': 5},   # 巳 (天德贵人)
            'month': {'g': 1, 'e': 0},   # 子
            'day': {'g': 0, 'e': 1},  # 丑
            'hour': {'g': 2, 'e': 3}     # 卯
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "e"))  # e indicates found from earth

        bazi_data = {
            'year': {'g': 6, 'e': 5},   # 庚 (天德贵人)
            'month': {'g': 1, 'e': 1},   # 丑
            'day': {'g': 6, 'e': 1},  # 庚 (天德贵人)
            'hour': {'g': 2, 'e': 3}     # 卯
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))  # g indicates found from god
        self.assertEqual(results[1], ('day', "g"))

        bazi_data = {
            'year': {'g': 6, 'e': 5},   # 庚
            'month': {'g': 1, 'e': 2},   # 寅
            'day': {'g': 6, 'e': 1},  # 庚
            'hour': {'g': 3, 'e': 3}     # 丁 (天德贵人)
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('hour', "g"))

        bazi_data = {
            'year': {'g': 6, 'e': 8},   # 申 (天德贵人)
            'month': {'g': 1, 'e': 3},   # 卯
            'day': {'g': 6, 'e': 1},  # 
            'hour': {'g': 3, 'e': 8}     # 申 (天德贵人)
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "e"))
        self.assertEqual(results[1], ('hour', "e"))

        bazi_data = {
            'year': {'g': 8, 'e': 8},   # 壬 (天德贵人)
            'month': {'g': 8, 'e': 4},   # 壬辰 (天德贵人)
            'day': {'g': 8, 'e': 1},  # 壬 (天德贵人)
            'hour': {'g': 8, 'e': 8}     # 壬 (天德贵人)
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))
        self.assertEqual(results[1], ('month', "g"))
        self.assertEqual(results[2], ('day', "g"))
        self.assertEqual(results[3], ('hour', "g"))

        bazi_data = {
            'year': {'g': 7, 'e': 8},   # 辛 (天德贵人)
            'month': {'g': 8, 'e': 5},   # 巳
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))

        bazi_data = {
            'year': {'g': 7, 'e': 11},   # 亥 (天德贵人)
            'month': {'g': 8, 'e': 6},   # 午
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "e"))

        bazi_data = {
            'year': {'g': 0, 'e': 11},   # 甲 (天德贵人)
            'month': {'g': 8, 'e': 7},   # 未
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))

        bazi_data = {
            'year': {'g': 9, 'e': 11},   # 癸 (天德贵人)
            'month': {'g': 8, 'e': 8},   # 申
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))

        bazi_data = {
            'year': {'g': 9, 'e': 2},   # 寅 (天德贵人)
            'month': {'g': 8, 'e': 9},   # 酉
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "e"))

        bazi_data = {
            'year': {'g': 2, 'e': 2},   # 丙 (天德贵人)
            'month': {'g': 8, 'e': 10},   # 戌
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))

        bazi_data = {
            'year': {'g': 1, 'e': 2},   # 乙 (天德贵人)
            'month': {'g': 8, 'e': 11},   # 亥
            'day': {'g': 8, 'e': 1},  # 
            'hour': {'g': 8, 'e': 8}     # 
        }
        results = bzshagod.find_tian_de(bazi_data)
        self.assertEqual(results[0], ('year', "g"))

class YueDeTests(unittest.TestCase):

    def test_all_cases(self):
        """Test that all month earth branches for 月德贵人"""
        bazi_data = {
            # year/day 壬 
            0: {
                'bz': {'year': {'g':8,'e':6}, 'month': {'g':0,'e':0}, 'day': {'g':8,'e':2}, 'hour': {'g':2,'e':2}},
                'check': {'year', 'day'}
            },
            # day/hour 庚 
            1: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':1,'e':1}, 'day': {'g':6,'e':2}, 'hour': {'g':6,'e':4}},
                'check': {'day', 'hour'}
            },
            # month/day 丙 
            2: {
                'bz': {'year': {'g':0,'e':6}, 'month': {'g':2,'e':2}, 'day': {'g':2,'e':10}, 'hour': {'g':0,'e':4}},
                'check': {'month', 'day'}
            },
            # year 甲
            3: {
                'bz': {'year': {'g':0,'e':8}, 'month': {'g':1,'e':3}, 'day': {'g':7,'e':1}, 'hour': {'g':2,'e':4}},
                'check': {'year'}
            },
            # month 壬
            4: {
                'bz': {'year': {'g':0,'e':2}, 'month': {'g':8,'e':4}, 'day': {'g':1,'e':1}, 'hour': {'g':3,'e':3}},
                'check': {'month'}
            },
            # day 庚
            5: {
                'bz': {'year': {'g':0,'e':0}, 'month': {'g':1,'e':5}, 'day': {'g':6,'e':2}, 'hour': {'g':2,'e':6}},
                'check': {'day'}
            },
            # hour 丙
            6: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':4,'e':6}, 'day': {'g':1,'e':1}, 'hour': {'g':2,'e':8}},
                'check': {'hour'}
            },
            # year/hour 甲
            7: {
                'bz': {'year': {'g':0,'e':6}, 'month': {'g':1,'e':7}, 'day': {'g':2,'e':4}, 'hour': {'g':0,'e':4}},
                'check': {'year', 'hour'}
            },
            # year/month/day 壬
            8: {
                'bz': {'year': {'g':8,'e':6}, 'month': {'g':8,'e':8}, 'day': {'g':8,'e':10}, 'hour': {'g':2,'e':2}},
                'check': {'year', 'month', 'day'}
            },
            # day/hour 庚
            9: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':1,'e':9}, 'day': {'g':6,'e':2}, 'hour': {'g':6,'e':6}},
                'check': {'day', 'hour'}
            },
            # year/month/day/hour 丙
            10: {
                'bz': {'year': {'g':2,'e':8}, 'month': {'g':2,'e':10}, 'day': {'g':2,'e':6}, 'hour': {'g':2,'e':2}},
                'check': {'year', 'month', 'day', 'hour'}
            },
            # year/hour 甲
            11: {
                'bz': {'year': {'g':0,'e':2}, 'month': {'g':1,'e':11}, 'day': {'g':1,'e':1}, 'hour': {'g':0,'e':6}},
                'check': {'year', 'hour'}
            },
            # none
            12: {
                'bz': {'year': {'g':1,'e':3}, 'month': {'g':0,'e':0}, 'day': {'g':3,'e':1}, 'hour': {'g':4,'e':6}},
                'check': {}
            },
        }

        for i in bazi_data:
            results = bzshagod.find_yue_de(bazi_data[i]['bz'])
            if len(bazi_data[i]['check']) > 0:
                ci = 0
                for pillar in bazi_data[i]['check']:
                    self.assertEqual(len(results), len(bazi_data[i]['check']), f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    self.assertIn(pillar, bazi_data[i]['check'], f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    ci += 1
            else:
                self.assertEqual(results, [])

class TaiJiTests(unittest.TestCase):

    def test_all_cases(self):
        """Test that all month earth branches for 太极贵人"""
        bazi_data = {
            # 甲日, year/hour 子午
            0: {
                'bz': {'year': {'g':8,'e':0}, 'month': {'g':0,'e':2}, 'day': {'g':0,'e':2}, 'hour': {'g':2,'e':6}},
                'check': {'year', 'hour'}
            },
            # 乙日, year/month 子
            1: {
                'bz': {'year': {'g':0,'e':0}, 'month': {'g':0,'e':0}, 'day': {'g':1,'e':1}, 'hour': {'g':6,'e':4}},
                'check': {'year' , 'month'}
            },
            # 丙日, month/hour 卯酉
            2: {
                'bz': {'year': {'g':0,'e':6}, 'month': {'g':3,'e':3}, 'day': {'g':2,'e':10}, 'hour': {'g':1,'e':9}},
                'check': {'month', 'hour'}
            },
            # 丁日, year 酉
            3: {
                'bz': {'year': {'g':3,'e':9}, 'month': {'g':1,'e':5}, 'day': {'g':3,'e':1}, 'hour': {'g':2,'e':4}},
                'check': {'year'}
            },
            # 戊日, year/month 辰丑
            4: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':9,'e':1}, 'day': {'g':4,'e':6}, 'hour': {'g':3,'e':5}},
                'check': {'year', 'month'}
            },
            # 己日, year/month/day/hour 辰戌丑未
            5: {
                'bz': {'year': {'g':1,'e':1}, 'month': {'g':2,'e':4}, 'day': {'g':5,'e':7}, 'hour': {'g':3,'e':10}},
                'check': {'year', 'month' , 'day', 'hour'}
            },
            # 庚日, day/hour 寅亥
            6: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':4,'e':6}, 'day': {'g':6,'e':2}, 'hour': {'g':3,'e':11}},
                'check': {'day', 'hour'}
            },
            # 辛日, year 寅
            7: {
                'bz': {'year': {'g':0,'e':2}, 'month': {'g':1,'e':7}, 'day': {'g':7,'e':5}, 'hour': {'g':0,'e':4}},
                'check': {'year'}
            },
            # 壬日, year/month/day 巳申
            8: {
                'bz': {'year': {'g':3,'e':5}, 'month': {'g':8,'e':8}, 'day': {'g':8,'e':8}, 'hour': {'g':2,'e':6}},
                'check': {'year', 'month', 'day'}
            },
            # 癸日, day/hour 巳申
            9: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':1,'e':9}, 'day': {'g':9,'e':5}, 'hour': {'g':6,'e':8}},
                'check': {'day', 'hour'}
            },
            # none, 丁日 - 卯酉
            10: {
                'bz': {'year': {'g':1,'e':5}, 'month': {'g':0,'e':0}, 'day': {'g':3,'e':1}, 'hour': {'g':4,'e':6}},
                'check': {}
            },
        }

        for i in bazi_data:
            results = bzshagod.find_taiji(bazi_data[i]['bz'])
            if len(bazi_data[i]['check']) > 0:
                ci = 0
                for pillar in bazi_data[i]['check']:
                    self.assertEqual(len(results), len(bazi_data[i]['check']), f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    self.assertIn(pillar, bazi_data[i]['check'], f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    ci += 1
            else:
                self.assertEqual(results, [])

class LuShenTests(unittest.TestCase):

    def test_all_cases(self):
        """Test all cases for 禄神"""
        bazi_data = {
            # 甲日, year/hour 寅
            0: {
                'bz': {'year': {'g':8,'e':2}, 'month': {'g':0,'e':4}, 'day': {'g':0,'e':4}, 'hour': {'g':2,'e':2}},
                'check': {'year', 'hour'}
            },
            # 乙日, year/month 卯
            1: {
                'bz': {'year': {'g':1,'e':3}, 'month': {'g':5,'e':3}, 'day': {'g':1,'e':1}, 'hour': {'g':6,'e':4}},
                'check': {'year' , 'month'}
            },
            # 丙日, month/hour 巳
            2: {
                'bz': {'year': {'g':0,'e':6}, 'month': {'g':3,'e':5}, 'day': {'g':2,'e':10}, 'hour': {'g':1,'e':5}},
                'check': {'month', 'hour'}
            },
            # 丁日, year 午
            3: {
                'bz': {'year': {'g':4,'e':6}, 'month': {'g':1,'e':5}, 'day': {'g':3,'e':1}, 'hour': {'g':2,'e':4}},
                'check': {'year'}
            },
            # 戊日, year/month 巳
            4: {
                'bz': {'year': {'g':1,'e':5}, 'month': {'g':9,'e':5}, 'day': {'g':4,'e':6}, 'hour': {'g':3,'e':7}},
                'check': {'year', 'month'}
            },
            # 己日, year/month/hour 午
            5: {
                'bz': {'year': {'g':2,'e':6}, 'month': {'g':2,'e':6}, 'day': {'g':5,'e':7}, 'hour': {'g':4,'e':6}},
                'check': {'year', 'month' , 'hour'}
            },
            # 庚日, year/month/day/hour 申
            6: {
                'bz': {'year': {'g':0,'e':8}, 'month': {'g':4,'e':8}, 'day': {'g':6,'e':8}, 'hour': {'g':6,'e':8}},
                'check': {'year', 'month', 'day', 'hour'}
            },
            # 辛日, year 酉
            7: {
                'bz': {'year': {'g':3,'e':9}, 'month': {'g':1,'e':7}, 'day': {'g':7,'e':5}, 'hour': {'g':0,'e':4}},
                'check': {'year'}
            },
            # 壬日, year/month 亥
            8: {
                'bz': {'year': {'g':3,'e':11}, 'month': {'g':7,'e':11}, 'day': {'g':8,'e':8}, 'hour': {'g':2,'e':6}},
                'check': {'year', 'month'}
            },
            # 癸日, month/hour 子
            9: {
                'bz': {'year': {'g':0,'e':4}, 'month': {'g':2,'e':0}, 'day': {'g':9,'e':5}, 'hour': {'g':6,'e':0}},
                'check': {'month', 'hour'}
            },
            # none, 乙日 - 卯
            10: {
                'bz': {'year': {'g':1,'e':5}, 'month': {'g':0,'e':0}, 'day': {'g':1,'e':1}, 'hour': {'g':4,'e':6}},
                'check': {}
            },
        }

        for i in bazi_data:
            results = bzshagod.find_lushen(bazi_data[i]['bz'])
            if len(bazi_data[i]['check']) > 0:
                ci = 0
                for pillar in bazi_data[i]['check']:
                    self.assertEqual(len(results), len(bazi_data[i]['check']), f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    self.assertIn(pillar, bazi_data[i]['check'], f"Item {i} {bazi_data[i]['check']}, calculated {results}")
                    ci += 1
            else:
                self.assertEqual(results, [])

def print_test_explanation():
    """Print explanation of what each test case verifies"""
    print("\nTest Cases Explanation:")
    print("1. test_find_tian_yi_basic:")
    print("   - Tests a basic case with 甲 day stem")
    print("   - Verifies both 阴贵人 (丑) and 阳贵人 (未) are found")
    
    print("\n2. test_find_tian_yi_no_matches:")
    print("   - Tests when no 天乙贵人 is present in any pillar")
    
    print("\n3. test_find_tian_yi_multiple_matches:")
    print("   - Tests with 戊 day stem")
    print("   - Verifies both 阴贵人 and 阳贵人 are found in different pillars")
    
    print("\n4. test_find_tian_yi_missing_hour:")
    print("   - Tests proper handling when hour pillar is not provided")
    
    print("\n5. test_all_stems_have_tian_yi:")
    print("   - Tests all 10 day stems")
    print("   - Verifies each stem can find both its 阴贵人 and 阳贵人")

if __name__ == '__main__':
    # Print test explanation before running tests
    print_test_explanation()
    print("\nRunning tests...")
    unittest.main(argv=['first-arg-is-ignored'], exit=False) 