"""
Analysis engine for KPI data
Provides AI-powered insights, recommendations, and pattern analysis using OpenAI
"""

import json
import asyncio
from typing import Dict, List, Any, Optional
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
import numpy as np
import logging
from datetime import datetime

from openai import AsyncOpenAI
from config.settings import settings
from ..models.kpi_models import KPIFile, AnalysisResult, ChartData, KpiCategory

logger = logging.getLogger(__name__)

class AnalysisEngine:
    """AI-powered KPI analysis engine"""
    
    def __init__(self):
        self.openai_client = None
        if settings.openai_api_key:
            self.openai_client = AsyncOpenAI(api_key=settings.openai_api_key)
    
    async def analyze_kpi_data(self, kpi_file: KPIFile) -> AnalysisResult:
        """Perform comprehensive KPI analysis"""
        try:
            # Calculate analysis components
            achievements = self._analyze_achievements(kpi_file)
            insights = await self._generate_insights(kpi_file)
            recommendations = await self._generate_recommendations(kpi_file)
            trends = self._analyze_trends(kpi_file)
            
            # Create analysis result
            result = AnalysisResult(
                file_id=1,  # This would come from database
                total_score=kpi_file.summary.final_score,
                perspective_scores=kpi_file.perspective_scores,
                achievements=achievements,
                recommendations=recommendations,
                insights=insights,
                trends=trends,
                charts_generated=False
            )
            
            return result
            
        except Exception as e:
            logger.error(f"Error analyzing KPI data: {str(e)}")
            raise
    
    async def generate_charts(self, kpi_file: KPIFile, analysis_result: AnalysisResult) -> List[ChartData]:
        """Generate interactive charts for KPI data"""
        charts = []
        
        try:
            # 1. Score Breakdown Chart
            score_chart = self._create_score_breakdown_chart(kpi_file)
            if score_chart:
                charts.append(score_chart)
            
            # 2. Trend Analysis Chart
            trend_chart = self._create_trend_chart(kpi_file)
            if trend_chart:
                charts.append(trend_chart)
            
            # 3. Achievement Status Chart
            achievement_chart = self._create_achievement_chart(kpi_file)
            if achievement_chart:
                charts.append(achievement_chart)
            
            # 4. Perspective Comparison Chart
            perspective_chart = self._create_perspective_comparison_chart(kpi_file)
            if perspective_chart:
                charts.append(perspective_chart)
            
            # 5. Monthly Performance Chart
            monthly_chart = self._create_monthly_performance_chart(kpi_file)
            if monthly_chart:
                charts.append(monthly_chart)
            
            return charts
            
        except Exception as e:
            logger.error(f"Error generating charts: {str(e)}")
            return charts
    
    def _analyze_achievements(self, kpi_file: KPIFile) -> Dict[str, Any]:
        """Analyze achievement data"""
        total_kpis = len(kpi_file.achievements.items)
        achieved = sum(1 for item in kpi_file.achievements.items if item.status.value == "Achieve")
        not_achieved = sum(1 for item in kpi_file.achievements.items if item.status.value == "Not Achieve")
        no_data = sum(1 for item in kpi_file.achievements.items if item.status.value == "No Data")
        
        return {
            "total_kpis": total_kpis,
            "achieved": achieved,
            "not_achieved": not_achieved,
            "no_data": no_data,
            "achievement_rate": kpi_file.achievement_rate,
            "achievement_percentage": (achieved / total_kpis * 100) if total_kpis > 0 else 0
        }
    
    async def _generate_insights(self, kpi_file: KPIFile) -> List[str]:
        """Generate AI-powered insights using OpenAI"""
        if not self.openai_client:
            return self._generate_basic_insights(kpi_file)
        
        try:
            # Prepare data for AI analysis
            analysis_data = {
                "summary": {
                    "name": kpi_file.summary.name,
                    "position": kpi_file.summary.position,
                    "total_score": kpi_file.summary.final_score,
                    "period": kpi_file.summary.performance_period
                },
                "perspective_scores": {k.value: v for k, v in kpi_file.perspective_scores.items()},
                "achievements": self._analyze_achievements(kpi_file),
                "kpi_details": []
            }
            
            # Add KPI details
            for kpi_sheet in kpi_file.kpi_sheets:
                kpi_info = {
                    "name": kpi_sheet.name,
                    "category": kpi_sheet.category.value,
                    "code": kpi_sheet.code,
                    "polarization": kpi_sheet.polarization.value,
                    "period_data": []
                }
                
                for period_data in kpi_sheet.period_data:
                    if period_data.realization is not None:
                        kpi_info["period_data"].append({
                            "period": period_data.period,
                            "realization": period_data.realization,
                            "target": period_data.target,
                            "score": period_data.score,
                            "status": period_data.status
                        })
                
                analysis_data["kpi_details"].append(kpi_info)
            
            # Generate prompt for OpenAI
            prompt = self._create_insights_prompt(analysis_data)
            
            response = await self.openai_client.chat.completions.create(
                model=settings.openai_model,
                messages=[
                    {"role": "system", "content": "You are an expert business analyst specializing in KPI analysis and performance improvement."},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=settings.openai_max_tokens,
                temperature=settings.openai_temperature
            )
            
            insights_text = response.choices[0].message.content
            
            # Parse insights into a list
            insights = [line.strip() for line in insights_text.split('\n') if line.strip()]
            
            return insights
            
        except Exception as e:
            logger.error(f"Error generating AI insights: {str(e)}")
            return self._generate_basic_insights(kpi_file)
    
    async def _generate_recommendations(self, kpi_file: KPIFile) -> List[str]:
        """Generate AI-powered recommendations using OpenAI"""
        if not self.openai_client:
            return self._generate_basic_recommendations(kpi_file)
        
        try:
            # Identify areas needing improvement
            problem_areas = []
            for category, score in kpi_file.perspective_scores.items():
                if score < 80:  # Below satisfactory level
                    problem_areas.append(f"{category.value}: {score:.1f}%")
            
            # Identify specific KPI issues
            kpi_issues = []
            for item in kpi_file.achievements.items:
                if item.status.value == "Not Achieve":
                    kpi_issues.append(f"{item.code}: {item.indicator}")
            
            prompt = f"""
            Based on the following KPI analysis for {kpi_file.summary.name} ({kpi_file.summary.position}):

            PERFORMANCE SUMMARY:
            - Total Score: {kpi_file.summary.final_score:.2f} Points
            - Achievement Rate: {kpi_file.achievement_rate:.1f}%

            PERSPECTIVE SCORES:
            {json.dumps({k.value: f"{v:.1f}%" for k, v in kpi_file.perspective_scores.items()}, indent=2)}

            PROBLEM AREAS:
            {json.dumps(problem_areas, indent=2)}

            UNDERPERFORMING KPIs:
            {json.dumps(kpi_issues[:10], indent=2)}

            Please provide 5-7 specific, actionable recommendations to improve performance. Focus on:
            1. Priority areas for immediate attention
            2. Specific actions for underperforming KPIs
            3. Strategic improvements for each perspective
            4. Timeline recommendations where applicable

            Format each recommendation as a clear, actionable bullet point.
            """
            
            response = await self.openai_client.chat.completions.create(
                model=settings.openai_model,
                messages=[
                    {"role": "system", "content": "You are an expert management consultant specializing in KPI improvement and organizational performance."},
                    {"role": "user", "content": prompt}
                ],
                max_tokens=settings.openai_max_tokens,
                temperature=settings.openai_temperature
            )
            
            recommendations_text = response.choices[0].message.content
            
            # Parse recommendations into a list
            recommendations = [line.strip() for line in recommendations_text.split('\n') if line.strip() and line.strip().startswith(('•', '-', '1.', '2.', '3.', '4.', '5.'))]
            
            return recommendations if recommendations else self._generate_basic_recommendations(kpi_file)
            
        except Exception as e:
            logger.error(f"Error generating AI recommendations: {str(e)}")
            return self._generate_basic_recommendations(kpi_file)
    
    def _analyze_trends(self, kpi_file: KPIFile) -> Dict[str, Any]:
        """Analyze trends in KPI data"""
        trends = {}
        
        # Analyze trends for each KPI sheet
        for kpi_sheet in kpi_file.kpi_sheets:
            if len(kpi_sheet.period_data) >= 2:
                # Calculate trend for this KPI
                recent_scores = [pd.score for pd in kpi_sheet.period_data[-3:] if pd.score is not None]
                earlier_scores = [pd.score for pd in kpi_sheet.period_data[:3] if pd.score is not None]
                
                if recent_scores and earlier_scores:
                    recent_avg = sum(recent_scores) / len(recent_scores)
                    earlier_avg = sum(earlier_scores) / len(earlier_scores)
                    
                    trend_direction = "improving" if recent_avg > earlier_avg else "declining"
                    trend_magnitude = abs(recent_avg - earlier_avg)
                    
                    trends[kpi_sheet.code] = {
                        "direction": trend_direction,
                        "magnitude": trend_magnitude,
                        "recent_average": recent_avg,
                        "earlier_average": earlier_avg
                    }
        
        return trends
    
    def _create_score_breakdown_chart(self, kpi_file: KPIFile) -> Optional[ChartData]:
        """Create score breakdown pie chart"""
        try:
            categories = [cat.value for cat in KpiCategory]
            scores = [kpi_file.perspective_scores.get(cat, 0) for cat in KpiCategory]
            
            # Validate data before creating chart
            if not scores or all(score == 0 for score in scores):
                logger.warning("No valid scores found for score breakdown chart - returning empty chart data")
                # Return empty chart structure instead of None
                return ChartData(
                    chart_type="pie",
                    title="KPI Score Breakdown by Perspective (No Data)",
                    data={"message": "No data available"}
                )
            
            # Filter out zero scores to avoid visual clutter
            valid_data = [(cat, score) for cat, score in zip(categories, scores) if score > 0]
            if not valid_data:
                logger.warning("All perspective scores are zero")
                return ChartData(
                    chart_type="pie",
                    title="KPI Score Breakdown by Perspective (No Data)",
                    data={"message": "No data available"}
                )
            
            filtered_categories, filtered_scores = zip(*valid_data)
            
            fig = go.Figure(data=[go.Pie(
                labels=filtered_categories,
                values=filtered_scores,
                hole=.3,
                textinfo='label+percent',
                textposition='outside',
                marker=dict(colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'][:len(filtered_categories)])
            )])
            
            fig.update_layout(
                title="KPI Score Breakdown by Perspective",
                font=dict(size=14),
                height=400
            )
            
            chart_data = fig.to_dict()
            
            return ChartData(
                chart_type="pie",
                title="KPI Score Breakdown by Perspective",
                data=chart_data
            )
            
        except Exception as e:
            logger.error(f"Error creating score breakdown chart: {str(e)}", exc_info=True)
            return ChartData(
                chart_type="pie",
                title="KPI Score Breakdown by Perspective (Error)",
                data={"error": str(e)}
            )
    
    def _create_trend_chart(self, kpi_file: KPIFile) -> Optional[ChartData]:
        """Create trend analysis chart"""
        try:
            # Collect time series data
            all_periods = set()
            for kpi_sheet in kpi_file.kpi_sheets:
                for period_data in kpi_sheet.period_data:
                    all_periods.add(period_data.period)
            
            sorted_periods = sorted(list(all_periods))
            
            # Create subplots
            fig = make_subplots(
                rows=2, cols=2,
                subplot_titles=[cat.value for cat in KpiCategory],
                specs=[[{"secondary_y": False}, {"secondary_y": False}],
                       [{"secondary_y": False}, {"secondary_y": False}]]
            )
            
            colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
            
            for idx, category in enumerate(KpiCategory):
                category_sheets = [sheet for sheet in kpi_file.kpi_sheets if sheet.category == category]
                
                if not category_sheets:
                    continue
                
                # Aggregate data for this category
                period_scores = {}
                for period in sorted_periods:
                    scores = []
                    for sheet in category_sheets:
                        for pd in sheet.period_data:
                            if pd.period == period and pd.score is not None:
                                scores.append(pd.score)
                    
                    if scores:
                        period_scores[period] = sum(scores) / len(scores)
                
                # Add trace
                periods = list(period_scores.keys())
                scores = list(period_scores.values())
                
                if periods and scores:
                    row = (idx // 2) + 1
                    col = (idx % 2) + 1
                    
                    fig.add_trace(
                        go.Scatter(
                            x=periods,
                            y=scores,
                            mode='lines+markers',
                            name=category.value,
                            line=dict(color=colors[idx]),
                            showlegend=False
                        ),
                        row=row, col=col
                    )
            
            fig.update_layout(
                title="KPI Trends by Perspective",
                height=600,
                font=dict(size=12)
            )
            
            chart_data = fig.to_dict()
            
            return ChartData(
                chart_type="line",
                title="KPI Performance Trends",
                data=chart_data
            )
            
        except Exception as e:
            logger.error(f"Error creating trend chart: {str(e)}")
            return None
    
    def _create_achievement_chart(self, kpi_file: KPIFile) -> Optional[ChartData]:
        """Create achievement status chart"""
        try:
            achievements = self._analyze_achievements(kpi_file)
            
            # Validate achievement data to prevent division by zero
            total_kpis = achievements['total_kpis']
            if total_kpis == 0:
                logger.warning("No KPIs found for achievement chart")
                return None
            
            achieved = achievements['achieved']
            not_achieved = achievements['not_achieved']
            no_data = achievements['no_data']
            
            # Only create chart if there's actual data
            if achieved + not_achieved + no_data == 0:
                logger.warning("No achievement data available")
                return None
            
            labels = ['Achieved', 'Not Achieved', 'No Data']
            values = [achieved, not_achieved, no_data]
            colors = ['#28a745', '#dc3545', '#ffc107']
            
            # Filter out zero values to avoid visual clutter
            non_zero_data = [(label, value, color) for label, value, color in zip(labels, values, colors) if value > 0]
            if not non_zero_data:
                logger.warning("All achievement values are zero")
                return None
            
            filtered_labels, filtered_values, filtered_colors = zip(*non_zero_data) if non_zero_data else ([], [], [])
            
            fig = go.Figure(data=[go.Bar(
                x=filtered_labels,
                y=filtered_values,
                marker_color=filtered_colors,
                text=filtered_values,
                textposition='auto'
            )])
            
            fig.update_layout(
                title="KPI Achievement Status",
                xaxis_title="Status",
                yaxis_title="Number of KPIs",
                height=400
            )
            
            chart_data = fig.to_dict()
            
            return ChartData(
                chart_type="bar",
                title="KPI Achievement Status",
                data=chart_data
            )
            
        except Exception as e:
            logger.error(f"Error creating achievement chart: {str(e)}")
            return None
    
    def _create_perspective_comparison_chart(self, kpi_file: KPIFile) -> Optional[ChartData]:
        """Create perspective comparison radar chart"""
        try:
            categories = [cat.value for cat in KpiCategory]
            scores = [kpi_file.perspective_scores.get(cat, 0) for cat in KpiCategory]
            
            fig = go.Figure()
            
            fig.add_trace(go.Scatterpolar(
                r=scores,
                theta=categories,
                fill='toself',
                name='Current Performance',
                line_color='#4ECDC4'
            ))
            
            # Add benchmark line at 80%
            benchmark_scores = [80] * len(categories)
            fig.add_trace(go.Scatterpolar(
                r=benchmark_scores,
                theta=categories,
                fill='toself',
                name='Target (80%)',
                line_color='#FF6B6B',
                line_dash='dash'
            ))
            
            fig.update_layout(
                polar=dict(
                    radialaxis=dict(
                        visible=True,
                        range=[0, 100]
                    )),
                title="KPI Performance by Perspective",
                height=500
            )
            
            chart_data = fig.to_dict()
            
            return ChartData(
                chart_type="polar",
                title="KPI Perspective Comparison",
                data=chart_data
            )
            
        except Exception as e:
            logger.error(f"Error creating perspective comparison chart: {str(e)}")
            return None
    
    def _create_monthly_performance_chart(self, kpi_file: KPIFile) -> Optional[ChartData]:
        """Create monthly performance chart"""
        try:
            # Collect all monthly data
            monthly_data = {}
            
            for kpi_sheet in kpi_file.kpi_sheets:
                for period_data in kpi_sheet.period_data:
                    month = period_data.period
                    if month not in monthly_data:
                        monthly_data[month] = []
                    
                    if period_data.score is not None:
                        monthly_data[month].append(period_data.score)
            
            # Validate that we have data
            if not monthly_data:
                logger.warning("No monthly data found for performance chart")
                return None
            
            # Calculate monthly averages
            months = sorted(monthly_data.keys())
            monthly_averages = []
            
            for month in months:
                scores = monthly_data[month]
                if scores:
                    monthly_averages.append(sum(scores) / len(scores))
                else:
                    monthly_averages.append(0)
            
            # Check if we have any valid data points
            if not monthly_averages or all(avg == 0 for avg in monthly_averages):
                logger.warning("All monthly averages are zero")
                return None
            
            fig = go.Figure()
            
            fig.add_trace(go.Scatter(
                x=months,
                y=monthly_averages,
                mode='lines+markers',
                name='Average KPI Score',
                line=dict(color='#45B7D1', width=3),
                marker=dict(size=8)
            ))
            
            # Add target line
            fig.add_hline(y=80, line_dash="dash", line_color="red", 
                         annotation_text="Target (80%)")
            
            fig.update_layout(
                title="Monthly KPI Performance Trend",
                xaxis_title="Month",
                yaxis_title="Average Score (%)",
                height=400
            )
            
            chart_data = fig.to_dict()
            
            return ChartData(
                chart_type="line",
                title="Monthly KPI Performance",
                data=chart_data
            )
            
        except Exception as e:
            logger.error(f"Error creating monthly performance chart: {str(e)}")
            return None
    
    def _create_insights_prompt(self, data: Dict[str, Any]) -> str:
        """Create prompt for insights generation"""
        return f"""
        Analyze the following KPI performance data and provide key insights:

        EMPLOYEE: {data['summary']['name']} - {data['summary']['position']}
        PERIOD: {data['summary']['period']}
        TOTAL SCORE: {data['summary']['total_score']:.2f} Points

        PERSPECTIVE SCORES:
        {json.dumps(data['perspective_scores'], indent=2)}

        ACHIEVEMENT SUMMARY:
        {json.dumps(data['achievements'], indent=2)}

        Please analyze this data and provide 5-7 key insights about:
        1. Overall performance strengths and weaknesses
        2. Patterns across different perspectives
        3. Areas of concern or improvement
        4. Positive trends or achievements
        5. Risk areas that need attention

        Present each insight as a clear, concise statement.
        """
    
    def _generate_basic_insights(self, kpi_file: KPIFile) -> List[str]:
        """Generate basic insights without AI"""
        insights = []
        
        # Overall performance insight
        if kpi_file.summary.final_score >= 90:
            insights.append(f"Excellent overall performance with total score of {kpi_file.summary.final_score:.2f} points (above 90)")
        elif kpi_file.summary.final_score >= 80:
            insights.append(f"Good overall performance with total score of {kpi_file.summary.final_score:.2f} points (meeting target standards)")
        else:
            insights.append(f"Performance below target with total score of {kpi_file.summary.final_score:.2f} points, requiring immediate attention")
        
        # Achievement rate insight
        if kpi_file.achievement_rate >= 80:
            insights.append(f"Strong achievement rate of {kpi_file.achievement_rate:.1f}%")
        else:
            insights.append(f"Achievement rate of {kpi_file.achievement_rate:.1f}% needs improvement")
        
        # Perspective analysis
        best_perspective = max(kpi_file.perspective_scores.items(), key=lambda x: x[1])
        worst_perspective = min(kpi_file.perspective_scores.items(), key=lambda x: x[1])
        
        insights.append(f"Strongest performance in {best_perspective[0].value} ({best_perspective[1]:.1f}%)")
        insights.append(f"Improvement needed in {worst_perspective[0].value} ({worst_perspective[1]:.1f}%)")
        
        return insights
    
    def _generate_basic_recommendations(self, kpi_file: KPIFile) -> List[str]:
        """Generate basic recommendations without AI"""
        recommendations = []
        
        # Low scoring areas
        low_scores = [(cat, score) for cat, score in kpi_file.perspective_scores.items() if score < 70]
        if low_scores:
            for cat, score in low_scores:
                recommendations.append(f"Focus on improving {cat.value} performance (current: {score:.1f}%)")
        
        # Achievement issues
        not_achieved = [item for item in kpi_file.achievements.items if item.status.value == "Not Achieve"]
        if not_achieved:
            recommendations.append(f"Address {len(not_achieved)} KPIs that are not meeting targets")
        
        # General recommendations
        recommendations.extend([
            "Develop action plans for underperforming areas",
            "Regular monitoring and feedback sessions",
            "Enhance training and skill development programs",
            "Implement continuous improvement processes"
        ])
        
        return recommendations

# Global analysis engine instance
analysis_engine = AnalysisEngine()