"""服务体验DNA解码系统"""

import pandas as pd
import numpy as np
from typing import List, Dict, Tuple, Optional
from pydantic import BaseModel, Field
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.cluster import DBSCAN
import re
import matplotlib.pyplot as plt
import seaborn as sns
from wordcloud import WordCloud
import plotly.express as px
import plotly.graph_objects as go
from collections import Counter
import networkx as nx


class ServiceExperienceInsight(BaseModel):
    """服务体验洞察"""
    主题名称: str = Field(description="主题名称")
    关键词: List[str] = Field(description="主题关键词")
    情感强度: float = Field(description="情感强度得分(-1到1)")
    问题类型: str = Field(description="问题分类")
    隐性不满指标: float = Field(description="隐性不满程度(0-1)")
    关联问题: List[str] = Field(description="关联的问题类型")
    典型推文: List[str] = Field(description="典型推文示例")


class ExperienceDNA(BaseModel):
    """体验DNA分析结果"""
    推文ID: str = Field(description="推文ID")
    主题分布: Dict[str, float] = Field(description="主题分布概率")
    情感强度: float = Field(description="情感强度得分")
    隐性不满: bool = Field(description="是否存在隐性不满")
    问题关联: List[str] = Field(description="关联的问题类型")
    关键洞察: str = Field(description="关键洞察描述")


class ServiceExperienceMap(BaseModel):
    """服务体验图谱"""
    节点: List[Dict] = Field(description="问题节点")
    边: List[Dict] = Field(description="关联关系")
    洞察: List[ServiceExperienceInsight] = Field(description="关键洞察")


class DNAResult(BaseModel):
    """DNA解码结果"""
    推文分析: ExperienceDNA = Field(description="单条推文分析")
    整体洞察: List[ServiceExperienceInsight] = Field(description="整体洞察")
    体验图谱: ServiceExperienceMap = Field(description="服务体验图谱")
    处置建议: List[str] = Field(description="处置建议")


class DNADecoder:
    """服务体验DNA解码器"""
    
    def __init__(self, data_path: str = "data/Tweets.csv"):
        self.data_path = data_path
        self.lda_model = None
        self.vectorizer = None
        self.topics = {}
        
    def load_data(self) -> pd.DataFrame:
        """加载数据"""
        df = pd.read_csv(self.data_path)
        return df
    
    def preprocess_text(self, text: str) -> str:
        """文本预处理"""
        if pd.isna(text):
            return ""
        
        # 基础清洗
        text = str(text).lower().strip()
        text = re.sub(r'[^\w\s]', '', text)  # 移除标点
        text = re.sub(r'\s+', ' ', text)  # 移除多余空格
        
        return text
    
    def train_lda_model(self, n_topics: int = 8) -> None:
        """训练LDA主题模型"""
        df = self.load_data()
        texts = df['text'].apply(self.preprocess_text).tolist()
        
        # 创建词袋模型
        self.vectorizer = CountVectorizer(
            max_df=0.95, min_df=2, 
            stop_words='english',
            max_features=1000
        )
        
        X = self.vectorizer.fit_transform(texts)
        
        # 训练LDA模型
        self.lda_model = LatentDirichletAllocation(
            n_components=n_topics,
            random_state=42,
            max_iter=10
        )
        
        self.lda_model.fit(X)
        
        # 提取主题关键词
        self._extract_topic_keywords()
    
    def _extract_topic_keywords(self) -> None:
        """提取主题关键词"""
        if self.lda_model is None or self.vectorizer is None:
            return
        
        feature_names = self.vectorizer.get_feature_names_out()
        
        for topic_idx, topic in enumerate(self.lda_model.components_):
            top_keywords_idx = topic.argsort()[-10:][::-1]
            top_keywords = [feature_names[i] for i in top_keywords_idx]
            
            # 根据关键词自动命名主题
            topic_name = self._generate_topic_name(top_keywords)
            self.topics[topic_idx] = {
                'name': topic_name,
                'keywords': top_keywords,
                'weight': topic.sum()
            }
    
    def _generate_topic_name(self, keywords: List[str]) -> str:
        """根据关键词生成主题名称"""
        # 常见航空服务关键词映射
        keyword_mapping = {
            'flight': '航班问题',
            'delay': '延误问题', 
            'cancel': '取消问题',
            'baggage': '行李问题',
            'service': '服务质量',
            'staff': '员工服务',
            'food': '餐饮服务',
            'seat': '座位舒适度',
            'time': '时间安排',
            'customer': '客户服务'
        }
        
        for keyword in keywords:
            if keyword in keyword_mapping:
                return keyword_mapping[keyword]
        
        return f"主题_{keywords[0] if keywords else '未知'}"
    
    def analyze_sentiment_intensity(self, text: str) -> float:
        """分析情感强度"""
        if pd.isna(text):
            return 0.0
        
        text_lower = str(text).lower()
        
        # 情感强度关键词和权重
        intensity_indicators = {
            # 强烈负面
            'terrible': -0.9, 'awful': -0.9, 'horrible': -0.9, 'disgusting': -0.9,
            'hate': -0.8, 'worst': -0.8, 'never again': -0.8,
            # 中等负面
            'bad': -0.6, 'poor': -0.6, 'disappointing': -0.6, 'frustrated': -0.6,
            # 轻微负面
            'ok': -0.3, 'average': -0.3, 'could be better': -0.3,
            # 轻微正面
            'good': 0.3, 'nice': 0.3, 'decent': 0.3,
            # 中等正面
            'great': 0.6, 'excellent': 0.6, 'wonderful': 0.6, 'satisfied': 0.6,
            # 强烈正面
            'amazing': 0.9, 'perfect': 0.9, 'best': 0.9, 'love': 0.9
        }
        
        # 感叹号和重复字符检测
        exclamation_count = text.count('!')
        repeat_patterns = len(re.findall(r'([a-z])\1{2,}', text_lower))
        
        intensity_score = 0.0
        matched_keywords = 0
        
        for keyword, weight in intensity_indicators.items():
            if keyword in text_lower:
                intensity_score += weight
                matched_keywords += 1
        
        # 计算平均强度
        if matched_keywords > 0:
            intensity_score /= matched_keywords
        
        # 考虑标点符号强度
        intensity_score += min(0.2, exclamation_count * 0.05)
        intensity_score += min(0.1, repeat_patterns * 0.03)
        
        # 限制在-1到1之间
        intensity_score = max(-1.0, min(1.0, intensity_score))
        
        return intensity_score
    
    def detect_implicit_dissatisfaction(self, text: str) -> Tuple[bool, float]:
        """检测隐性不满"""
        if pd.isna(text):
            return False, 0.0
        
        text_lower = str(text).lower()
        
        # 隐性不满指标
        implicit_indicators = {
            # 委婉表达
            'wish': 0.3, 'hope': 0.3, 'would be nice': 0.4,
            'could have been': 0.4, 'might want to': 0.3,
            # 对比表达
            'but': 0.4, 'however': 0.5, 'although': 0.4,
            # 疑问表达
            'why': 0.3, 'how come': 0.4, 'is this normal': 0.5,
            # 讽刺表达
            'interesting': 0.6, 'surprising': 0.5, 'unexpected': 0.4
        }
        
        # 检测指标
        indicator_score = 0.0
        for indicator, weight in implicit_indicators.items():
            if indicator in text_lower:
                indicator_score += weight
        
        # 情感强度较低但存在问题的文本
        sentiment_intensity = self.analyze_sentiment_intensity(text)
        
        # 隐性不满判断逻辑
        is_implicit = False
        confidence = 0.0
        
        if indicator_score > 0.5 and abs(sentiment_intensity) < 0.3:
            is_implicit = True
            confidence = min(1.0, indicator_score * 0.8)
        elif indicator_score > 0.3 and sentiment_intensity < -0.1:
            is_implicit = True
            confidence = min(1.0, indicator_score * 0.6)
        
        return is_implicit, confidence
    
    def build_experience_map(self, df: pd.DataFrame) -> ServiceExperienceMap:
        """构建服务体验图谱"""
        # 提取问题和关联
        problems = df['negativereason'].dropna().unique()
        
        nodes = []
        edges = []
        
        # 创建节点
        for i, problem in enumerate(problems):
            problem_df = df[df['negativereason'] == problem]
            sentiment_avg = problem_df['airline_sentiment_confidence'].mean()
            
            nodes.append({
                'id': problem,
                'label': problem,
                'size': len(problem_df),
                'sentiment': sentiment_avg
            })
        
        # 创建关联边（基于共同出现）
        for i, problem1 in enumerate(problems):
            for j, problem2 in enumerate(problems):
                if i < j:
                    # 计算关联强度（简单实现）
                    co_occurrence = len(df[
                        (df['negativereason'] == problem1) | 
                        (df['negativereason'] == problem2)
                    ])
                    
                    if co_occurrence > 10:  # 阈值
                        edges.append({
                            'source': problem1,
                            'target': problem2,
                            'weight': co_occurrence
                        })
        
        # 生成洞察
        insights = self._generate_insights(df)
        
        return ServiceExperienceMap(
            节点=nodes,
            边=edges,
            洞察=insights
        )
    
    def _generate_insights(self, df: pd.DataFrame) -> List[ServiceExperienceInsight]:
        """生成关键洞察"""
        insights = []
        
        # 分析最常见的负面原因
        top_problems = df['negativereason'].value_counts().head(5)
        
        for problem, count in top_problems.items():
            problem_df = df[df['negativereason'] == problem]
            
            # 分析相关推文的情感强度
            sentiment_scores = problem_df['text'].apply(self.analyze_sentiment_intensity)
            avg_sentiment = sentiment_scores.mean()
            
            # 检测隐性不满
            implicit_scores = problem_df['text'].apply(
                lambda x: self.detect_implicit_dissatisfaction(x)[1]
            )
            avg_implicit = implicit_scores.mean()
            
            # 提取典型推文
            typical_tweets = problem_df['text'].head(3).tolist()
            
            insight = ServiceExperienceInsight(
                主题名称=problem,
                关键词=[problem],
                情感强度=avg_sentiment,
                问题类型=problem,
                隐性不满指标=avg_implicit,
                关联问题=[],
                典型推文=typical_tweets
            )
            
            insights.append(insight)
        
        return insights
    
    def decode_experience_dna(self, tweet_text: str) -> DNAResult:
        """解码单条推文的体验DNA"""
        if self.lda_model is None:
            self.train_lda_model()
        
        # 预处理文本
        processed_text = self.preprocess_text(tweet_text)
        
        # 主题分析
        if self.vectorizer is not None:
            X = self.vectorizer.transform([processed_text])
            topic_distribution = self.lda_model.transform(X)[0]
            
            # 转换为字典格式
            topic_dist_dict = {}
            for topic_idx, prob in enumerate(topic_distribution):
                if topic_idx in self.topics:
                    topic_name = self.topics[topic_idx]['name']
                    topic_dist_dict[topic_name] = float(prob)
        else:
            topic_dist_dict = {}
        
        # 情感强度分析
        sentiment_intensity = self.analyze_sentiment_intensity(tweet_text)
        
        # 隐性不满检测
        is_implicit, implicit_confidence = self.detect_implicit_dissatisfaction(tweet_text)
        
        # 构建体验DNA
        experience_dna = ExperienceDNA(
            推文ID="current_tweet",
            主题分布=topic_dist_dict,
            情感强度=sentiment_intensity,
            隐性不满=is_implicit,
            问题关联=list(topic_dist_dict.keys()),
            关键洞察=self._generate_tweet_insight(tweet_text, sentiment_intensity, is_implicit)
        )
        
        # 加载数据生成整体洞察和体验图谱
        df = self.load_data()
        overall_insights = self._generate_insights(df)
        experience_map = self.build_experience_map(df)
        
        # 生成处置建议
        recommendations = self._generate_recommendations(experience_dna)
        
        return DNAResult(
            推文分析=experience_dna,
            整体洞察=overall_insights,
            体验图谱=experience_map,
            处置建议=recommendations
        )
    
    def _generate_tweet_insight(self, text: str, sentiment: float, is_implicit: bool) -> str:
        """生成推文关键洞察"""
        insights = []
        
        if sentiment < -0.5:
            insights.append("客户表现出强烈不满情绪")
        elif sentiment < -0.1:
            insights.append("客户存在轻微不满")
        
        if is_implicit:
            insights.append("存在隐性不满迹象")
        
        if 'delay' in text.lower():
            insights.append("涉及延误问题")
        if 'food' in text.lower():
            insights.append("涉及餐饮服务")
        if 'baggage' in text.lower():
            insights.append("涉及行李问题")
        
        return "; ".join(insights) if insights else "无明显问题特征"
    
    def _generate_recommendations(self, dna: ExperienceDNA) -> List[str]:
        """生成处置建议"""
        recommendations = []
        
        if dna.情感强度 < -0.5:
            recommendations.append("立即联系客户，表达歉意并了解具体情况")
        elif dna.情感强度 < -0.1:
            recommendations.append("主动跟进客户反馈，提供解决方案")
        
        if dna.隐性不满:
            recommendations.append("注意客户可能未直接表达的深层不满")
        
        if '延误问题' in dna.问题关联:
            recommendations.append("提供延误补偿方案和后续航班安排")
        if '行李问题' in dna.问题关联:
            recommendations.append("启动行李追踪和赔偿流程")
        if '餐饮服务' in dna.问题关联:
            recommendations.append("收集具体反馈改进餐饮质量")
        
        return recommendations


def create_dna_decoder() -> DNADecoder:
    """创建DNA解码器实例"""
    return DNADecoder()