from dataclasses import dataclass
from breed_health_info import breed_health_info
from breed_noise_info import breed_noise_info

@dataclass
class UserPreferences:

    """使用者偏好設定的資料結構"""
    living_space: str  # "apartment", "house_small", "house_large"
    yard_access: str  # "no_yard", "shared_yard", "private_yard" 
    exercise_time: int  # minutes per day
    exercise_type: str  # "light_walks", "moderate_activity", "active_training" 
    grooming_commitment: str  # "low", "medium", "high"
    experience_level: str  # "beginner", "intermediate", "advanced"
    time_availability: str  # "limited", "moderate", "flexible" 
    has_children: bool
    children_age: str  # "toddler", "school_age", "teenager"
    noise_tolerance: str  # "low", "medium", "high"
    space_for_play: bool
    other_pets: bool
    climate: str  # "cold", "moderate", "hot"
    health_sensitivity: str = "medium"
    barking_acceptance: str = None

    def __post_init__(self):
        """在初始化後運行,用於設置派生值"""
        if self.barking_acceptance is None:
            self.barking_acceptance = self.noise_tolerance


@staticmethod
def calculate_breed_bonus(breed_info: dict, user_prefs: 'UserPreferences') -> float:
    """計算品種額外加分"""
    bonus = 0.0
    temperament = breed_info.get('Temperament', '').lower()
    
    # 1. 壽命加分(最高0.05)
    try:
        lifespan = breed_info.get('Lifespan', '10-12 years')
        years = [int(x) for x in lifespan.split('-')[0].split()[0:1]]
        longevity_bonus = min(0.05, (max(years) - 10) * 0.01)
        bonus += longevity_bonus
    except:
        pass

    # 2. 性格特徵加分(最高0.15)
    positive_traits = {
        'friendly': 0.05,           
        'gentle': 0.05,
        'patient': 0.05,
        'intelligent': 0.04,
        'adaptable': 0.04,
        'affectionate': 0.04,
        'easy-going': 0.03,         
        'calm': 0.03                
    }
    
    negative_traits = {
        'aggressive': -0.08,        
        'stubborn': -0.06,
        'dominant': -0.06,
        'aloof': -0.04,
        'nervous': -0.05,           
        'protective': -0.04         
    }
    
    personality_score = sum(value for trait, value in positive_traits.items() if trait in temperament)
    personality_score += sum(value for trait, value in negative_traits.items() if trait in temperament)
    bonus += max(-0.15, min(0.15, personality_score))

    # 3. 適應性加分(最高0.1)
    adaptability_bonus = 0.0
    if breed_info.get('Size') == "Small" and user_prefs.living_space == "apartment":
        adaptability_bonus += 0.05
    if 'adaptable' in temperament or 'versatile' in temperament:
        adaptability_bonus += 0.05
    bonus += min(0.1, adaptability_bonus)

    # 4. 家庭相容性(最高0.1)
    if user_prefs.has_children:
        family_traits = {
            'good with children': 0.06,  
            'patient': 0.05,
            'gentle': 0.05,
            'tolerant': 0.04,           
            'playful': 0.03             
        }
        unfriendly_traits = {
            'aggressive': -0.08,        
            'nervous': -0.07,
            'protective': -0.06,
            'territorial': -0.05        
        }
        
        # 年齡評估這樣能更細緻
        age_adjustments = {
            'toddler': {'bonus_mult': 0.7, 'penalty_mult': 1.3},
            'school_age': {'bonus_mult': 1.0, 'penalty_mult': 1.0},
            'teenager': {'bonus_mult': 1.2, 'penalty_mult': 0.8}
        }
        
        adj = age_adjustments.get(user_prefs.children_age, 
                                {'bonus_mult': 1.0, 'penalty_mult': 1.0})
        
        family_bonus = sum(value for trait, value in family_traits.items() 
                          if trait in temperament) * adj['bonus_mult']
        family_penalty = sum(value for trait, value in unfriendly_traits.items() 
                           if trait in temperament) * adj['penalty_mult']
        
        bonus += min(0.15, max(-0.2, family_bonus + family_penalty))

    
    # 5. 專門技能加分(最高0.1)
    skill_bonus = 0.0
    special_abilities = {
        'working': 0.03,
        'herding': 0.03,
        'hunting': 0.03,
        'tracking': 0.03,
        'agility': 0.02
    }
    for ability, value in special_abilities.items():
        if ability in temperament.lower():
            skill_bonus += value
    bonus += min(0.1, skill_bonus)

    return min(0.5, max(-0.25, bonus))


@staticmethod
def calculate_additional_factors(breed_info: dict, user_prefs: 'UserPreferences') -> dict:
    """計算額外的評估因素"""
    factors = {
        'versatility': 0.0,        # 多功能性
        'trainability': 0.0,       # 可訓練度
        'energy_level': 0.0,       # 能量水平
        'grooming_needs': 0.0,     # 美容需求
        'social_needs': 0.0,       # 社交需求
        'weather_adaptability': 0.0 # 氣候適應性
    }
    
    temperament = breed_info.get('Temperament', '').lower()
    size = breed_info.get('Size', 'Medium')
    
    # 1. 多功能性評估
    versatile_traits = ['intelligent', 'adaptable', 'trainable', 'athletic']
    working_roles = ['working', 'herding', 'hunting', 'sporting', 'companion']
    
    trait_score = sum(0.2 for trait in versatile_traits if trait in temperament)
    role_score = sum(0.2 for role in working_roles if role in breed_info.get('Description', '').lower())
    
    factors['versatility'] = min(1.0, trait_score + role_score)
    
    # 2. 可訓練度評估
    trainable_traits = {
        'intelligent': 0.3,
        'eager to please': 0.3,
        'trainable': 0.2,
        'quick learner': 0.2
    }
    factors['trainability'] = min(1.0, sum(value for trait, value in trainable_traits.items() 
                                         if trait in temperament))
    
    # 3. 能量水平評估
    exercise_needs = breed_info.get('Exercise Needs', 'MODERATE').upper()
    energy_levels = {
        'VERY HIGH': 1.0,
        'HIGH': 0.8,
        'MODERATE': 0.6,
        'LOW': 0.4,
        'VARIES': 0.6
    }
    factors['energy_level'] = energy_levels.get(exercise_needs, 0.6)
    
    # 4. 美容需求評估
    grooming_needs = breed_info.get('Grooming Needs', 'MODERATE').upper()
    grooming_levels = {
        'HIGH': 1.0,
        'MODERATE': 0.6,
        'LOW': 0.3
    }
    coat_penalty = 0.2 if any(term in breed_info.get('Description', '').lower() 
                             for term in ['long coat', 'double coat']) else 0
    factors['grooming_needs'] = min(1.0, grooming_levels.get(grooming_needs, 0.6) + coat_penalty)
    
    # 5. 社交需求評估
    social_traits = ['friendly', 'social', 'affectionate', 'people-oriented']
    antisocial_traits = ['independent', 'aloof', 'reserved']
    
    social_score = sum(0.25 for trait in social_traits if trait in temperament)
    antisocial_score = sum(-0.2 for trait in antisocial_traits if trait in temperament)
    factors['social_needs'] = min(1.0, max(0.0, social_score + antisocial_score))
    
    # 6. 氣候適應性評估
    climate_terms = {
        'cold': ['thick coat', 'winter', 'cold climate'],
        'hot': ['short coat', 'warm climate', 'heat tolerant'],
        'moderate': ['adaptable', 'all climate']
    }
    
    climate_matches = sum(1 for term in climate_terms[user_prefs.climate] 
                        if term in breed_info.get('Description', '').lower())
    factors['weather_adaptability'] = min(1.0, climate_matches * 0.3 + 0.4)  # 基礎分0.4

    return factors


def calculate_compatibility_score(breed_info: dict, user_prefs: UserPreferences) -> dict:
    """計算品種與使用者條件的相容性分數的優化版本"""
    try:
        print(f"Processing breed: {breed_info.get('Breed', 'Unknown')}")
        print(f"Breed info keys: {breed_info.keys()}")
        
        if 'Size' not in breed_info:
            print("Missing Size information")
            raise KeyError("Size information missing")
            
        def calculate_space_score(size: str, living_space: str, has_yard: bool, exercise_needs: str) -> float:
            """空間分數計算"""
            # 基礎空間需求矩陣
            base_scores = {
                "Small": {"apartment": 0.95, "house_small": 1.0, "house_large": 0.90},
                "Medium": {"apartment": 0.60, "house_small": 0.90, "house_large": 1.0},
                "Large": {"apartment": 0.30, "house_small": 0.75, "house_large": 1.0},
                "Giant": {"apartment": 0.15, "house_small": 0.55, "house_large": 1.0}
            }
            
            # 取得基礎分數
            base_score = base_scores.get(size, base_scores["Medium"])[living_space]
            
            # 運動需求調整
            exercise_adjustments = {
                "Very High": -0.15 if living_space == "apartment" else 0,
                "High": -0.10 if living_space == "apartment" else 0,
                "Moderate": 0,
                "Low": 0.05 if living_space == "apartment" else 0
            }
            
            adjustments = exercise_adjustments.get(exercise_needs.strip(), 0)
            
            # 院子獎勵
            if has_yard and size in ["Large", "Giant"]:
                adjustments += 0.10
            elif has_yard:
                adjustments += 0.05
                
            return min(1.0, max(0.1, base_score + adjustments))

        def calculate_exercise_score(breed_needs: str, user_time: int) -> float:
            """運動需求計算"""
            exercise_needs = {
                'VERY HIGH': {'min': 120, 'ideal': 150, 'max': 180},
                'HIGH': {'min': 90, 'ideal': 120, 'max': 150},
                'MODERATE': {'min': 45, 'ideal': 60, 'max': 90},
                'LOW': {'min': 20, 'ideal': 30, 'max': 45},
                'VARIES': {'min': 30, 'ideal': 60, 'max': 90}
            }
            
            breed_need = exercise_needs.get(breed_needs.strip().upper(), exercise_needs['MODERATE'])
            
            # 計算匹配度
            if user_time >= breed_need['ideal']:
                if user_time > breed_need['max']:
                    return 0.9  # 稍微降分,因為可能過度運動
                return 1.0
            elif user_time >= breed_need['min']:
                return 0.8 + (user_time - breed_need['min']) / (breed_need['ideal'] - breed_need['min']) * 0.2
            else:
                return max(0.3, 0.8 * (user_time / breed_need['min']))

        def calculate_grooming_score(breed_needs: str, user_commitment: str, breed_size: str) -> float:
            """美容需求計算"""
            # 基礎分數矩陣
            base_scores = {
                "High": {"low": 0.3, "medium": 0.7, "high": 1.0},
                "Moderate": {"low": 0.5, "medium": 0.9, "high": 1.0},
                "Low": {"low": 1.0, "medium": 0.95, "high": 0.8}
            }
            
            # 取得基礎分數
            base_score = base_scores.get(breed_needs, base_scores["Moderate"])[user_commitment]
            
            # 體型影響調整
            size_adjustments = {
                "Large": {"low": -0.2, "medium": -0.1, "high": 0},
                "Giant": {"low": -0.3, "medium": -0.15, "high": 0},
            }
            
            if breed_size in size_adjustments:
                adjustment = size_adjustments[breed_size].get(user_commitment, 0)
                base_score = max(0.2, base_score + adjustment)
                
            return base_score
            

        def calculate_experience_score(care_level: str, user_experience: str, temperament: str) -> float:
            """飼養經驗需求計算"""
            # 初始化 temperament_adjustments,確保所有路徑都有值
            temperament_adjustments = 0.0
            
            # 降低初學者的基礎分數
            base_scores = {
                "High": {"beginner": 0.15, "intermediate": 0.70, "advanced": 1.0},     
                "Moderate": {"beginner": 0.40, "intermediate": 0.85, "advanced": 1.0}, 
                "Low": {"beginner": 0.75, "intermediate": 0.95, "advanced": 1.0}       
            }
            
            score = base_scores.get(care_level, base_scores["Moderate"])[user_experience]
            
            # 擴展性格特徵評估
            temperament_lower = temperament.lower()
            
            if user_experience == "beginner":
                # 增加更多特徵評估
                difficult_traits = {
                    'stubborn': -0.12,     
                    'independent': -0.10,
                    'dominant': -0.10,
                    'strong-willed': -0.08,
                    'protective': -0.06,     
                    'energetic': -0.05      
                }
                
                easy_traits = {
                    'gentle': 0.06,         
                    'friendly': 0.06,
                    'eager to please': 0.06,
                    'patient': 0.05,
                    'adaptable': 0.05,      
                    'calm': 0.04           
                }
                
                # 更精確的特徵影響計算
                temperament_adjustments = sum(value for trait, value in easy_traits.items() if trait in temperament_lower)
                temperament_adjustments += sum(value for trait, value in difficult_traits.items() if trait in temperament_lower)
                
                # 品種特定調整
                if "terrier" in breed_info['Description'].lower():
                    temperament_adjustments -= 0.1  # 梗類犬對新手不友善
            
            elif user_experience == "intermediate":
                # 中級飼主的調整較溫和
                if any(trait in temperament_lower for trait in ['gentle', 'friendly', 'patient']):
                    temperament_adjustments += 0.03
                if any(trait in temperament_lower for trait in ['stubborn', 'independent']):
                    temperament_adjustments -= 0.02
            
            else:  # advanced
                # 資深飼主能處理更具挑戰性的犬種
                if any(trait in temperament_lower for trait in ['stubborn', 'independent', 'dominant']):
                    temperament_adjustments += 0.02  # 反而可能是優點
                if any(trait in temperament_lower for trait in ['protective', 'energetic']):
                    temperament_adjustments += 0.03
            
            final_score = max(0.2, min(1.0, score + temperament_adjustments))
            return final_score

        def calculate_health_score(breed_name: str) -> float:
            """計算品種健康分數"""
            if breed_name not in breed_health_info:
                return 0.5

            health_notes = breed_health_info[breed_name]['health_notes'].lower()
            
            # 嚴重健康問題(降低0.15分)
            severe_conditions = [
                'hip dysplasia',
                'heart disease',
                'progressive retinal atrophy',
                'bloat',
                'epilepsy',
                'degenerative myelopathy',
                'von willebrand disease'
            ]
            
            # 中度健康問題(降低0.1分)
            moderate_conditions = [
                'allergies',
                'eye problems',
                'joint problems',
                'hypothyroidism',
                'ear infections',
                'skin issues'
            ]
            
            # 輕微健康問題(降低0.05分)
            minor_conditions = [
                'dental issues',
                'weight gain tendency',
                'minor allergies',
                'seasonal allergies'
            ]

            # 計算基礎健康分數
            health_score = 1.0
            
            # 根據問題嚴重程度扣分
            severe_count = sum(1 for condition in severe_conditions if condition in health_notes)
            moderate_count = sum(1 for condition in moderate_conditions if condition in health_notes)
            minor_count = sum(1 for condition in minor_conditions if condition in health_notes)
            
            health_score -= (severe_count * 0.15)
            health_score -= (moderate_count * 0.1)
            health_score -= (minor_count * 0.05)

            # 壽命影響
            try:
                lifespan = breed_health_info[breed_name].get('average_lifespan', '10-12')
                years = float(lifespan.split('-')[0])
                if years < 8:
                    health_score *= 0.9
                elif years > 13:
                    health_score *= 1.1
            except:
                pass

            # 特殊健康優勢
            if 'generally healthy' in health_notes or 'hardy breed' in health_notes:
                health_score *= 1.1

            return max(0.2, min(1.0, health_score))

        def calculate_noise_score(breed_name: str, user_noise_tolerance: str) -> float:
            """計算品種噪音分數"""
            if breed_name not in breed_noise_info:
                return 0.5

            noise_info = breed_noise_info[breed_name]
            noise_level = noise_info['noise_level'].lower()
            noise_notes = noise_info['noise_notes'].lower()

            # 基礎噪音分數矩陣
            base_scores = {
                'low': {'low': 1.0, 'medium': 0.9, 'high': 0.8},
                'medium': {'low': 0.7, 'medium': 1.0, 'high': 0.9},
                'high': {'low': 0.4, 'medium': 0.7, 'high': 1.0},
                'varies': {'low': 0.6, 'medium': 0.8, 'high': 0.9}
            }

            # 獲取基礎分數
            base_score = base_scores.get(noise_level, {'low': 0.7, 'medium': 0.8, 'high': 0.6})[user_noise_tolerance]

            # 吠叫原因評估
            barking_reasons_penalty = 0
            problematic_triggers = [
                ('separation anxiety', -0.15),
                ('excessive barking', -0.12),
                ('territorial', -0.08),
                ('alert barking', -0.05),
                ('attention seeking', -0.05)
            ]

            for trigger, penalty in problematic_triggers:
                if trigger in noise_notes:
                    barking_reasons_penalty += penalty

            # 可訓練性補償
            trainability_bonus = 0
            if 'responds well to training' in noise_notes:
                trainability_bonus = 0.1
            elif 'can be trained' in noise_notes:
                trainability_bonus = 0.05

            # 特殊情況
            special_adjustments = 0
            if 'rarely barks' in noise_notes:
                special_adjustments += 0.1
            if 'howls' in noise_notes and user_noise_tolerance == 'low':
                special_adjustments -= 0.1

            final_score = base_score + barking_reasons_penalty + trainability_bonus + special_adjustments
            
            return max(0.2, min(1.0, final_score))

        # 計算所有基礎分數
        scores = {
            'space': calculate_space_score(
                breed_info['Size'], 
                user_prefs.living_space,
                user_prefs.space_for_play,
                breed_info.get('Exercise Needs', 'Moderate')
            ),
            'exercise': calculate_exercise_score(
                breed_info.get('Exercise Needs', 'Moderate'),
                user_prefs.exercise_time
            ),
            'grooming': calculate_grooming_score(
                breed_info.get('Grooming Needs', 'Moderate'),
                user_prefs.grooming_commitment.lower(),
                breed_info['Size']
            ),
            'experience': calculate_experience_score(
                breed_info.get('Care Level', 'Moderate'),
                user_prefs.experience_level,
                breed_info.get('Temperament', '')
            ),
            'health': calculate_health_score(breed_info.get('Breed', '')),
            'noise': calculate_noise_score(breed_info.get('Breed', ''), user_prefs.noise_tolerance)
        }

        # 優化權重配置
        weights = {
            'space': 0.28,      
            'exercise': 0.18,   
            'grooming': 0.12,   
            'experience': 0.22, 
            'health': 0.12,     
            'noise': 0.08      
        }

        # 計算加權總分
        weighted_score = sum(score * weights[category] for category, score in scores.items())
        
        # 擴大分數差異
        def amplify_score(score):
            # 使用指數函數擴大差異
            amplified = pow((score - 0.5) * 2, 3) / 8 + score
            return max(0.65, min(0.95, amplified))  # 限制在65%-95%範圍內
        
        final_score = amplify_score(weighted_score)

        # 四捨五入所有分數
        scores = {k: round(v, 4) for k, v in scores.items()}
        scores['overall'] = round(final_score, 4)

        return scores

    except Exception as e:
        print(f"Error details: {str(e)}")
        print(f"breed_info: {breed_info}")
        # print(f"Error in calculate_compatibility_score: {str(e)}")
        return {k: 0.5 for k in ['space', 'exercise', 'grooming', 'experience', 'health', 'noise', 'overall']}