
"""
Phase 4: Resolution Performance & SLA Compliance Analytics
Cycle-time analysis, bottleneck detection, state transitions, duration variance
"""

import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from pathlib import Path
import warnings
warnings.filterwarnings('ignore')

# Paths
OUTPUT_DIR = Path("/app/workspace/temp_files")
IMG_DIR = Path("/app/workspace/assets/images")

print("=" * 80)
print("PHASE 4: RESOLUTION PERFORMANCE & SLA COMPLIANCE ANALYTICS")
print("=" * 80)

# Load cleaned data
incidents_df = pd.read_pickle(OUTPUT_DIR / "incidents_cleaned.pkl")
tasks_df = pd.read_pickle(OUTPUT_DIR / "tasks_cleaned.pkl")

# ============================================================================
# 1. RESOLUTION CYCLE-TIME DISTRIBUTION MODELING
# ============================================================================
print("\n⏱️ RESOLUTION CYCLE-TIME ANALYSIS")
print("-" * 40)

# Filter valid resolution times (positive values only)
incidents_valid = incidents_df[incidents_df['Resolution_Hours'] > 0].copy()
tasks_valid = tasks_df[tasks_df['Business_Duration_Hours'] >= 0].copy()

# Histogram with KDE-style distribution
fig_cycle = make_subplots(
    rows=1, cols=2,
    subplot_titles=['Incident Resolution Time Distribution (Hours)', 
                    'Task Business Duration Distribution (Hours)']
)

# Incidents - capped at 500 hours for visualization
incidents_capped = incidents_valid[incidents_valid['Resolution_Hours'] <= 500]['Resolution_Hours']
fig_cycle.add_trace(
    go.Histogram(x=incidents_capped, nbinsx=50, 
                 marker_color='#E63946', name='Incidents', opacity=0.7),
    row=1, col=1
)

# Tasks - capped at 500 hours
tasks_capped = tasks_valid[tasks_valid['Business_Duration_Hours'] <= 500]['Business_Duration_Hours']
fig_cycle.add_trace(
    go.Histogram(x=tasks_capped, nbinsx=50,
                 marker_color='#457B9D', name='Tasks', opacity=0.7),
    row=1, col=2
)

fig_cycle.update_layout(template='plotly_white', height=400, showlegend=False)
fig_cycle.write_html(IMG_DIR / "resolution_cycle_distribution.html")
fig_cycle.write_image(IMG_DIR / "resolution_cycle_distribution.png")
print("✓ Saved: resolution_cycle_distribution")

# Summary statistics
print("\n📋 RESOLUTION TIME STATISTICS:")
print("\n  INCIDENTS:")
print(f"    Mean: {incidents_valid['Resolution_Hours'].mean():.1f} hours ({incidents_valid['Resolution_Hours'].mean()/24:.1f} days)")
print(f"    Median: {incidents_valid['Resolution_Hours'].median():.1f} hours ({incidents_valid['Resolution_Hours'].median()/24:.1f} days)")
print(f"    Std Dev: {incidents_valid['Resolution_Hours'].std():.1f} hours")
print(f"    25th Percentile: {incidents_valid['Resolution_Hours'].quantile(0.25):.1f} hours")
print(f"    75th Percentile: {incidents_valid['Resolution_Hours'].quantile(0.75):.1f} hours")
print(f"    90th Percentile: {incidents_valid['Resolution_Hours'].quantile(0.90):.1f} hours")
print(f"    95th Percentile: {incidents_valid['Resolution_Hours'].quantile(0.95):.1f} hours")

print("\n  TASKS:")
print(f"    Mean: {tasks_valid['Business_Duration_Hours'].mean():.1f} hours ({tasks_valid['Business_Duration_Hours'].mean()/24:.1f} days)")
print(f"    Median: {tasks_valid['Business_Duration_Hours'].median():.1f} hours ({tasks_valid['Business_Duration_Hours'].median()/24:.1f} days)")
print(f"    Std Dev: {tasks_valid['Business_Duration_Hours'].std():.1f} hours")
print(f"    25th Percentile: {tasks_valid['Business_Duration_Hours'].quantile(0.25):.1f} hours")
print(f"    75th Percentile: {tasks_valid['Business_Duration_Hours'].quantile(0.75):.1f} hours")
print(f"    90th Percentile: {tasks_valid['Business_Duration_Hours'].quantile(0.90):.1f} hours")
print(f"    95th Percentile: {tasks_valid['Business_Duration_Hours'].quantile(0.95):.1f} hours")

# ============================================================================
# 2. BOTTLENECK DETECTION USING IQR & PERCENTILES
# ============================================================================
print("\n🔍 BOTTLENECK DETECTION")
print("-" * 40)

# IQR-based outlier detection for tasks
Q1 = tasks_valid['Business_Duration_Hours'].quantile(0.25)
Q3 = tasks_valid['Business_Duration_Hours'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

print(f"\n  IQR Analysis (Tasks):")
print(f"    Q1: {Q1:.1f} hours")
print(f"    Q3: {Q3:.1f} hours")
print(f"    IQR: {IQR:.1f} hours")
print(f"    Lower Bound: {lower_bound:.1f} hours")
print(f"    Upper Bound: {upper_bound:.1f} hours")

# Identify outliers
outliers_low = tasks_valid[tasks_valid['Business_Duration_Hours'] < lower_bound]
outliers_high = tasks_valid[tasks_valid['Business_Duration_Hours'] > upper_bound]

print(f"\n  Outlier Summary:")
print(f"    Low outliers (< {lower_bound:.0f}h): {len(outliers_low):,} ({len(outliers_low)/len(tasks_valid)*100:.1f}%)")
print(f"    High outliers (> {upper_bound:.0f}h): {len(outliers_high):,} ({len(outliers_high)/len(tasks_valid)*100:.1f}%)")

# Extreme outliers (> 95th percentile)
extreme_threshold = tasks_valid['Business_Duration_Hours'].quantile(0.95)
extreme_cases = tasks_valid[tasks_valid['Business_Duration_Hours'] > extreme_threshold]
print(f"    Extreme (> {extreme_threshold:.0f}h): {len(extreme_cases):,} ({len(extreme_cases)/len(tasks_valid)*100:.1f}%)")

# Visualization of outliers
fig_outliers = go.Figure()
fig_outliers.add_trace(go.Box(
    y=tasks_valid['Business_Duration_Hours'],
    name='Business Duration',
    boxpoints='outliers',
    marker_color='#457B9D'
))
fig_outliers.add_hline(y=upper_bound, line_dash="dash", line_color="red", 
                       annotation_text=f"Upper Bound: {upper_bound:.0f}h")
fig_outliers.add_hline(y=extreme_threshold, line_dash="dot", line_color="orange",
                       annotation_text=f"95th Pctl: {extreme_threshold:.0f}h")
fig_outliers.update_layout(
    title='Task Duration Box Plot with Outlier Thresholds',
    template='plotly_white', height=400
)
fig_outliers.write_html(IMG_DIR / "duration_outlier_detection.html")
fig_outliers.write_image(IMG_DIR / "duration_outlier_detection.png")
print("✓ Saved: duration_outlier_detection")

# Duration by Category for bottleneck identification
duration_by_cat = tasks_valid.groupby('Subcategory')['Business_Duration_Hours'].agg(
    ['mean', 'median', 'count', 'std']
).round(1)
duration_by_cat = duration_by_cat.sort_values('median', ascending=False)

fig_cat_dur = px.box(
    tasks_valid, x='Subcategory', y='Business_Duration_Hours',
    title='Task Resolution Duration by Subcategory',
    labels={'Subcategory': 'Subcategory', 'Business_Duration_Hours': 'Hours'},
    color='Subcategory'
)
fig_cat_dur.update_layout(
    template='plotly_white', height=500,
    xaxis={'tickangle': 45},
    showlegend=False
)
fig_cat_dur.write_html(IMG_DIR / "duration_by_subcategory.html")
fig_cat_dur.write_image(IMG_DIR / "duration_by_subcategory.png")
print("✓ Saved: duration_by_subcategory")

# ============================================================================
# 3. STATE TRANSITION & THROUGHPUT ANALYSIS
# ============================================================================
print("\n📊 STATE TRANSITION ANALYSIS")
print("-" * 40)

# State distribution and transition analysis
state_dist = tasks_df['State'].value_counts()
print("\n  Task State Distribution:")
for state, count in state_dist.items():
    print(f"    {state}: {count:,} ({count/len(tasks_df)*100:.1f}%)")

# Create funnel analysis for states
fig_funnel = go.Figure(go.Funnel(
    y=['Total Opened', 'In Progress', 'Closed Complete', 'Closed Incomplete'],
    x=[len(tasks_df), 
       len(tasks_df[tasks_df['State'].isin(['In Progress', 'Open', 'Pending Vendor', 'Pending Customer'])]),
       len(tasks_df[tasks_df['State'] == 'Closed Complete']),
       len(tasks_df[tasks_df['State'] == 'Closed Incomplete'])],
    textinfo='value+percent previous',
    marker_color=['#457B9D', '#2A9D8F', '#28A745', '#DC3545']
))
fig_funnel.update_layout(title='Task State Funnel Analysis', template='plotly_white', height=400)
fig_funnel.write_html(IMG_DIR / "state_funnel_analysis.html")
fig_funnel.write_image(IMG_DIR / "state_funnel_analysis.png")
print("✓ Saved: state_funnel_analysis")

# Time-in-state analysis (approximation based on Created/Updated gaps)
tasks_df['Updated_parsed'] = pd.to_datetime(tasks_df['Updated'], errors='coerce')
tasks_df['Time_To_First_Update_Hours'] = (
    tasks_df['Updated_parsed'] - tasks_df['Opened']
).dt.total_seconds() / 3600

# State progression over time for sample
fig_state_time = px.scatter(
    tasks_df.sample(min(5000, len(tasks_df))), 
    x='Opened', y='Business_Duration_Hours',
    color='State',
    title='Task Resolution Time Over Time by State',
    labels={'Opened': 'Open Date', 'Business_Duration_Hours': 'Duration (Hours)'},
    color_discrete_map={
        'Closed Complete': '#28A745',
        'Closed Incomplete': '#DC3545',
        'Pending Vendor': '#FFC107',
        'Pending Customer': '#17A2B8',
        'Closed Skipped': '#6C757D'
    }
)
fig_state_time.update_layout(template='plotly_white', height=450)
fig_state_time.write_html(IMG_DIR / "state_duration_timeline.html")
fig_state_time.write_image(IMG_DIR / "state_duration_timeline.png")
print("✓ Saved: state_duration_timeline")

# ============================================================================
# 4. BUSINESS vs CALENDAR DURATION VARIANCE ANALYSIS
# ============================================================================
print("\n📅 BUSINESS vs CALENDAR DURATION ANALYSIS")
print("-" * 40)

# Calculate variance metrics
tasks_valid['Duration_Ratio'] = np.where(
    tasks_valid['Total_Elapsed_Hours'] > 0,
    tasks_valid['Business_Duration_Hours'] / tasks_valid['Total_Elapsed_Hours'],
    np.nan
)

# Filter valid ratios
ratio_valid = tasks_valid[tasks_valid['Duration_Ratio'].notna() & (tasks_valid['Duration_Ratio'] <= 1)]

print(f"\n  Duration Ratio (Business/Total):")
print(f"    Mean: {ratio_valid['Duration_Ratio'].mean()*100:.1f}%")
print(f"    Median: {ratio_valid['Duration_Ratio'].median()*100:.1f}%")
print(f"    25th Percentile: {ratio_valid['Duration_Ratio'].quantile(0.25)*100:.1f}%")
print(f"    75th Percentile: {ratio_valid['Duration_Ratio'].quantile(0.75)*100:.1f}%")

# Identify cases where work stalls (low business duration ratio but high calendar time)
stalled = ratio_valid[ratio_valid['Duration_Ratio'] < 0.1]  # Less than 10% active work time
print(f"\n  Potential Stalled Cases (<10% active time): {len(stalled):,} ({len(stalled)/len(ratio_valid)*100:.1f}%)")

# Visualization of duration comparison
fig_dur_compare = go.Figure()
fig_dur_compare.add_trace(go.Box(
    y=tasks_valid['Business_Duration_Hours'],
    name='Business Duration',
    marker_color='#2A9D8F'
))
fig_dur_compare.add_trace(go.Box(
    y=tasks_valid['Total_Elapsed_Hours'],
    name='Calendar Duration',
    marker_color='#E63946'
))
fig_dur_compare.update_layout(
    title='Business Duration vs Calendar Duration Comparison',
    template='plotly_white', height=400
)
fig_dur_compare.write_html(IMG_DIR / "business_vs_calendar_duration.html")
fig_dur_compare.write_image(IMG_DIR / "business_vs_calendar_duration.png")
print("✓ Saved: business_vs_calendar_duration")

# Duration ratio distribution
fig_ratio_dist = px.histogram(
    ratio_valid, x='Duration_Ratio', nbins=50,
    title='Distribution of Work Efficiency (Business/Calendar Ratio)',
    labels={'Duration_Ratio': 'Efficiency Ratio'},
    color_discrete_sequence=['#2A9D8F']
)
fig_ratio_dist.add_vline(x=ratio_valid['Duration_Ratio'].median(), line_dash="dash", 
                        line_color="red", annotation_text=f"Median: {ratio_valid['Duration_Ratio'].median():.2f}")
fig_ratio_dist.update_layout(template='plotly_white', height=400, bargap=0.1)
fig_ratio_dist.write_html(IMG_DIR / "efficiency_ratio_distribution.html")
fig_ratio_dist.write_image(IMG_DIR / "efficiency_ratio_distribution.png")
print("✓ Saved: efficiency_ratio_distribution")

# Duration ratio by assignment group
ratio_by_group = tasks_valid.groupby('Assignment group').agg({
    'Duration_Ratio': 'median',
    'Business_Duration_Hours': 'median',
    'Total_Elapsed_Hours': 'median',
    'Number': 'count'
}).rename(columns={'Number': 'Count'}).round(3)

fig_ratio_group = px.bar(
    ratio_by_group, x=ratio_by_group.index, y='Duration_Ratio',
    title='Work Efficiency Ratio by Assignment Group',
    labels={'Assignment group': 'Team', 'Duration_Ratio': 'Median Efficiency Ratio'},
    color='Duration_Ratio',
    color_continuous_scale='RdYlGn'
)
fig_ratio_group.update_layout(template='plotly_white', height=400)
fig_ratio_group.write_html(IMG_DIR / "efficiency_by_assignment_group.html")
fig_ratio_group.write_image(IMG_DIR / "efficiency_by_assignment_group.png")
print("✓ Saved: efficiency_by_assignment_group")

# ============================================================================
# 5. THROUGHPUT & VELOCITY METRICS
# ============================================================================
print("\n📈 THROUGHPUT & VELOCITY METRICS")
print("-" * 40)

# Weekly throughput
weekly_throughput = tasks_df.groupby(tasks_df['Opened'].dt.to_period('W')).size()
print(f"\n  Weekly Task Throughput:")
print(f"    Mean: {weekly_throughput.mean():.1f} tasks/week")
print(f"    Max: {weekly_throughput.max():,} tasks/week")
print(f"    Min: {weekly_throughput.min():,} tasks/week")

fig_throughput = px.line(
    x=[str(x) for x in weekly_throughput.index], 
    y=weekly_throughput.values,
    title='Weekly Task Throughput - 2025',
    labels={'x': 'Week', 'y': 'Tasks Completed'},
    markers=True
)
fig_throughput.update_traces(line_color='#457B9D', marker_size=8)
fig_throughput.update_layout(template='plotly_white', height=400)
fig_throughput.write_html(IMG_DIR / "weekly_throughput.html")
fig_throughput.write_image(IMG_DIR / "weekly_throughput.png")
print("✓ Saved: weekly_throughput")

# Resolution rate over time (success rate by week)
tasks_df['Week'] = tasks_df['Opened'].dt.to_period('W')
tasks_df['Week_str'] = tasks_df['Week'].astype(str)
weekly_success = tasks_df.groupby('Week_str').apply(
    lambda x: (x['Resolution_Outcome'] == 'Success').mean() * 100
).reset_index()
weekly_success.columns = ['Week', 'Success_Rate']

fig_success_rate = px.bar(
    weekly_success, x='Week', y='Success_Rate',
    title='Weekly Task Success Rate - 2025',
    labels={'Week': 'Week', 'Success_Rate': 'Success Rate (%)'},
    color='Success_Rate',
    color_continuous_scale='RdYlGn'
)
fig_success_rate.update_layout(template='plotly_white', height=400)
fig_success_rate.add_hline(y=80, line_dash="dash", line_color="green", 
                          annotation_text="80% Target")
fig_success_rate.write_html(IMG_DIR / "weekly_success_rate.html")
fig_success_rate.write_image(IMG_DIR / "weekly_success_rate.png")
print("✓ Saved: weekly_success_rate")

# ============================================================================
# KEY PERFORMANCE INDICATORS SUMMARY
# ============================================================================
print("\n📋 RESOLUTION PERFORMANCE KEY METRICS")
print("-" * 40)

print("\n⏱️ CYCLE TIME METRICS:")
print(f"  Incident Mean: {incidents_valid['Resolution_Hours'].mean():.1f}h ({incidents_valid['Resolution_Hours'].mean()/24:.1f} days)")
print(f"  Task Mean: {tasks_valid['Business_Duration_Hours'].mean():.1f}h ({tasks_valid['Business_Duration_Hours'].mean()/24:.1f} days)")
print(f"  Task Median: {tasks_valid['Business_Duration_Hours'].median():.1f}h ({tasks_valid['Business_Duration_Hours'].median()/24:.1f} days)")

print("\n✅ RESOLUTION QUALITY:")
print(f"  Overall Success Rate: {(tasks_df['Resolution_Outcome']=='Success').mean()*100:.1f}%")
print(f"  Failure Rate: {(tasks_df['Resolution_Outcome']=='Failure').mean()*100:.1f}%")

print("\n⚡ EFFICIENCY METRICS:")
print(f"  Mean Efficiency Ratio: {ratio_valid['Duration_Ratio'].mean()*100:.1f}%")
print(f"  Median Efficiency Ratio: {ratio_valid['Duration_Ratio'].median()*100:.1f}%")
print(f"  Stalled Cases: {len(stalled):,} ({len(stalled)/len(ratio_valid)*100:.1f}%)")

print("\n📊 THROUGHPUT:")
print(f"  Weekly Mean: {weekly_throughput.mean():.1f} tasks")
print(f"  Peak Week: {weekly_throughput.max():,} tasks")

print("\n✅ RESOLUTION PERFORMANCE ANALYSIS COMPLETE")
print(f"✓ {len(list(IMG_DIR.glob('*resolution*')))} visualizations saved")
print(f"✓ {len(list(IMG_DIR.glob('*duration*')))} duration-related visualizations saved")
