from typing import Dict, List, Any, Optional
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
from io import BytesIO
import base64
from datetime import datetime, timedelta

class ReportUtils:
    """Utility functions for PDF report generation"""
    
    @staticmethod
    def format_currency(amount: float, currency: str = "₹") -> str:
        """Format currency with proper formatting"""
        if amount >= 10000000:  # 1 crore
            return f"{currency}{amount/10000000:.1f}Cr"
        elif amount >= 100000:  # 1 lakh
            return f"{currency}{amount/100000:.1f}L"
        elif amount >= 1000:  # 1 thousand
            return f"{currency}{amount/1000:.1f}K"
        else:
            return f"{currency}{amount:,.0f}"
    
    @staticmethod
    def calculate_growth_rate(current: float, previous: float) -> float:
        """Calculate growth rate percentage"""
        if previous == 0:
            return 0.0
        return ((current - previous) / previous) * 100
    
    @staticmethod
    def get_performance_grade(score: float) -> str:
        """Get performance grade based on score"""
        if score >= 90:
            return "A+"
        elif score >= 80:
            return "A"
        elif score >= 70:
            return "B+"
        elif score >= 60:
            return "B"
        elif score >= 50:
            return "C"
        else:
            return "D"
    
    @staticmethod
    def create_kpi_summary_table(kpis: List[Dict]) -> List[List[str]]:
        """Create formatted KPI summary table data"""
        table_data = [["KPI", "Current", "Target", "Status", "Grade"]]
        
        for kpi in kpis:
            status_symbol = "✓" if "Good" in kpi.get('status', '') else "⚠" if "Fair" in kpi.get('status', '') else "✗"
            grade = ReportUtils.get_performance_grade(kpi.get('value', 0))
            
            formatted_value = ReportUtils.format_currency(kpi['value']) if kpi.get('unit') == '₹' else f"{kpi['value']:.1f}{kpi.get('unit', '')}"
            formatted_target = ReportUtils.format_currency(kpi.get('target', 0)) if kpi.get('unit') == '₹' else f"{kpi.get('target', 0):.1f}{kpi.get('unit', '')}"
            
            table_data.append([
                kpi['name'],
                formatted_value,
                formatted_target,
                f"{status_symbol} {kpi.get('status', 'Unknown')}",
                grade
            ])
        
        return table_data
    
    @staticmethod
    def generate_trend_analysis(data_points: List[float], periods: List[str]) -> Dict[str, Any]:
        """Generate trend analysis from data points"""
        if len(data_points) < 2:
            return {"trend": "insufficient_data", "direction": "neutral", "growth_rate": 0}
        
        # Calculate trend
        recent_avg = sum(data_points[-3:]) / len(data_points[-3:]) if len(data_points) >= 3 else data_points[-1]
        earlier_avg = sum(data_points[:3]) / len(data_points[:3]) if len(data_points) >= 3 else data_points[0]
        
        growth_rate = ReportUtils.calculate_growth_rate(recent_avg, earlier_avg)
        
        if growth_rate > 5:
            trend = "improving"
            direction = "upward"
        elif growth_rate < -5:
            trend = "declining"
            direction = "downward"
        else:
            trend = "stable"
            direction = "neutral"
        
        return {
            "trend": trend,
            "direction": direction,
            "growth_rate": growth_rate,
            "recent_average": recent_avg,
            "earlier_average": earlier_avg
        }
    
    @staticmethod
    def create_benchmark_comparison(current_metrics: Dict, industry_benchmarks: Dict) -> List[Dict]:
        """Create benchmark comparison analysis"""
        comparisons = []
        
        for metric, current_value in current_metrics.items():
            benchmark_value = industry_benchmarks.get(metric, 0)
            
            if benchmark_value > 0:
                variance = ((current_value - benchmark_value) / benchmark_value) * 100
                
                if variance > 10:
                    performance = "Above Benchmark"
                    status = "excellent"
                elif variance > 0:
                    performance = "At Benchmark"
                    status = "good"
                elif variance > -10:
                    performance = "Near Benchmark"
                    status = "fair"
                else:
                    performance = "Below Benchmark"
                    status = "poor"
                
                comparisons.append({
                    "metric": metric,
                    "current_value": current_value,
                    "benchmark_value": benchmark_value,
                    "variance_percentage": variance,
                    "performance": performance,
                    "status": status
                })
        
        return comparisons
    
    @staticmethod
    def calculate_business_ratios(financial_data: Dict) -> Dict[str, float]:
        """Calculate key business ratios"""
        ratios = {}
        
        # Profitability Ratios
        if financial_data.get('revenue', 0) > 0:
            ratios['gross_profit_margin'] = (financial_data.get('gross_profit', 0) / financial_data['revenue']) * 100
            ratios['net_profit_margin'] = (financial_data.get('net_profit', 0) / financial_data['revenue']) * 100
            ratios['operating_margin'] = (financial_data.get('operating_profit', 0) / financial_data['revenue']) * 100
        
        # Efficiency Ratios
        if financial_data.get('total_assets', 0) > 0:
            ratios['asset_turnover'] = financial_data.get('revenue', 0) / financial_data['total_assets']
            ratios['roa'] = (financial_data.get('net_profit', 0) / financial_data['total_assets']) * 100
        
        # Investment Ratios
        if financial_data.get('total_investment', 0) > 0:
            ratios['roi'] = (financial_data.get('net_profit', 0) / financial_data['total_investment']) * 100
            ratios['payback_period'] = financial_data['total_investment'] / max(financial_data.get('annual_cash_flow', 1), 1)
        
        return ratios
    
    @staticmethod
    def generate_recommendations(performance_data: Dict) -> List[str]:
        """Generate performance-based recommendations"""
        recommendations = []
        
        # Financial recommendations
        if performance_data.get('roi', 0) < 15:
            recommendations.append("Consider optimizing cost structure to improve ROI - target 15%+ return on investment")
        
        if performance_data.get('gross_margin', 0) < 25:
            recommendations.append("Focus on improving gross margins through better supplier negotiations and pricing strategies")
        
        if performance_data.get('inventory_turnover', 0) < 10:
            recommendations.append("Optimize inventory management to achieve faster turnover and reduce carrying costs")
        
        # Operational recommendations
        if performance_data.get('sales_per_sqft', 0) < 2000:
            recommendations.append("Improve space utilization and merchandising to increase sales per square foot")
        
        if performance_data.get('conversion_rate', 0) < 15:
            recommendations.append("Enhance customer experience and staff training to improve conversion rates")
        
        # Strategic recommendations
        if performance_data.get('market_share', 0) < 5:
            recommendations.append("Develop marketing strategies to increase market penetration and brand awareness")
        
        if len(recommendations) == 0:
            recommendations.append("Performance is strong across key metrics - focus on maintaining current standards and exploring expansion opportunities")
        
        return recommendations
    
    @staticmethod
    def create_executive_summary(group_data: Dict, performance_metrics: Dict) -> Dict[str, Any]:
        """Create executive summary for reports"""
        summary = {
            "group_name": group_data.get('group_name', 'Unknown'),
            "participants": group_data.get('participants', 0),
            "overall_score": performance_metrics.get('overall_score', 0),
            "grade": ReportUtils.get_performance_grade(performance_metrics.get('overall_score', 0)),
            "key_strengths": [],
            "improvement_areas": [],
            "financial_highlight": "",
            "operational_highlight": ""
        }
        
        # Identify strengths and improvement areas
        if performance_metrics.get('roi', 0) > 20:
            summary['key_strengths'].append("Excellent return on investment")
        elif performance_metrics.get('roi', 0) < 10:
            summary['improvement_areas'].append("ROI below industry standards")
        
        if performance_metrics.get('gross_margin', 0) > 30:
            summary['key_strengths'].append("Strong gross margins")
        elif performance_metrics.get('gross_margin', 0) < 20:
            summary['improvement_areas'].append("Gross margins need improvement")
        
        if performance_metrics.get('sales_per_sqft', 0) > 2500:
            summary['key_strengths'].append("Excellent space productivity")
        elif performance_metrics.get('sales_per_sqft', 0) < 1500:
            summary['improvement_areas'].append("Space utilization below optimal")
        
        # Financial highlight
        revenue = performance_metrics.get('revenue', 0)
        profit = performance_metrics.get('net_profit', 0)
        summary['financial_highlight'] = f"Revenue: {ReportUtils.format_currency(revenue)}, Net Profit: {ReportUtils.format_currency(profit)}"
        
        # Operational highlight
        stores = performance_metrics.get('total_stores', 0)
        conversion = performance_metrics.get('conversion_rate', 0)
        summary['operational_highlight'] = f"Planned Stores: {stores}, Conversion Rate: {conversion:.1f}%"
        
        return summary

class ChartGenerator:
    """Generate charts for PDF reports"""
    
    @staticmethod
    def create_kpi_gauge_chart(value: float, target: float, title: str) -> BytesIO:
        """Create a gauge chart for KPI visualization"""
        fig, ax = plt.subplots(figsize=(6, 4))
        
        # Create gauge
        theta = (value / target) * 180 if target > 0 else 0
        theta = min(180, max(0, theta))  # Clamp between 0 and 180
        
        # Draw gauge arc
        arc = patches.Arc((0.5, 0), 1, 1, angle=0, theta1=0, theta2=180, 
                         linewidth=20, color='lightgray')
        ax.add_patch(arc)
        
        # Draw value arc
        value_arc = patches.Arc((0.5, 0), 1, 1, angle=0, theta1=0, theta2=theta,
                               linewidth=20, color='green' if theta > 120 else 'orange' if theta > 60 else 'red')
        ax.add_patch(value_arc)
        
        # Add needle
        needle_x = 0.5 + 0.4 * np.cos(np.radians(180 - theta))
        needle_y = 0.4 * np.sin(np.radians(180 - theta))
        ax.plot([0.5, needle_x], [0, needle_y], 'k-', linewidth=3)
        
        # Add labels
        ax.text(0.5, -0.2, f"{value:.1f}", ha='center', va='center', fontsize=16, fontweight='bold')
        ax.text(0.5, -0.3, title, ha='center', va='center', fontsize=12)
        ax.text(0.1, 0.1, "0", ha='center', va='center', fontsize=10)
        ax.text(0.9, 0.1, f"{target:.0f}", ha='center', va='center', fontsize=10)
        
        ax.set_xlim(0, 1)
        ax.set_ylim(-0.4, 0.6)
        ax.set_aspect('equal')
        ax.axis('off')
        
        # Save to buffer
        buffer = BytesIO()
        plt.savefig(buffer, format='png', bbox_inches='tight', dpi=150)
        buffer.seek(0)
        plt.close()
        
        return buffer
    
    @staticmethod
    def create_performance_radar_chart(metrics: Dict[str, float], targets: Dict[str, float]) -> BytesIO:
        """Create radar chart for performance visualization"""
        import numpy as np
        
        categories = list(metrics.keys())
        values = [metrics[cat] / targets.get(cat, 1) * 100 for cat in categories]  # Normalize to percentage of target
        
        # Number of variables
        N = len(categories)
        
        # Compute angle for each axis
        angles = [n / float(N) * 2 * np.pi for n in range(N)]
        angles += angles[:1]  # Complete the circle
        
        # Add values for complete circle
        values += values[:1]
        
        # Create plot
        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(projection='polar'))
        
        # Draw the plot
        ax.plot(angles, values, 'o-', linewidth=2, label='Current Performance')
        ax.fill(angles, values, alpha=0.25)
        
        # Add target line (100%)
        target_line = [100] * (N + 1)
        ax.plot(angles, target_line, '--', linewidth=1, color='red', label='Target (100%)')
        
        # Add labels
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(categories)
        ax.set_ylim(0, 150)
        ax.set_yticks([25, 50, 75, 100, 125])
        ax.set_yticklabels(['25%', '50%', '75%', '100%', '125%'])
        ax.grid(True)
        
        plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
        plt.title('Performance vs Targets', size=16, fontweight='bold', pad=20)
        
        # Save to buffer
        buffer = BytesIO()
        plt.savefig(buffer, format='png', bbox_inches='tight', dpi=150)
        buffer.seek(0)
        plt.close()
        
        return buffer

# Industry benchmarks for comparison
INDUSTRY_BENCHMARKS = {
    "roi": 18.0,
    "gross_margin_percentage": 28.0,
    "net_margin_percentage": 12.0,
    "sales_per_sqft": 2200.0,
    "inventory_turnover": 11.0,
    "conversion_rate": 16.0,
    "customer_footfall": 14000,
    "average_transaction_value": 750.0
}