import math
from datetime import datetime
from astral import LocationInfo
from astral.sun import elevation, azimuth
import pytz

class DebugSolarSimulation:
    def __init__(self):
        self.panel_power = 700  # watts
        self.bifaciality_factor = 0.80
        self.dni_clear_sky = 900  # W/m²
        self.ground_albedo = 0.15
        
        # Location: Lago Brown, Chile
        self.location = LocationInfo("Lago Brown", "Chile", "America/Santiago", -47.3919449, -72.3174973)
        self.timezone = pytz.timezone('America/Santiago')
        
    def get_solar_position(self, date, hour, minute=0):
        """Get precise solar position using astronomical calculations"""
        dt = datetime(date.year, date.month, date.day, hour, minute, 0)
        dt = self.timezone.localize(dt)
        
        # Get solar elevation and azimuth
        solar_elevation = elevation(self.location.observer, dt)
        solar_azimuth = azimuth(self.location.observer, dt)
        
        return solar_elevation, solar_azimuth
    
    def calculate_angle_of_incidence(self, solar_elevation, solar_azimuth, panel_tilt, panel_azimuth):
        """Calculate angle of incidence between sun and panel surface"""
        if solar_elevation <= 0:
            return 0
        
        # Convert to radians
        se_rad = math.radians(solar_elevation)
        sa_rad = math.radians(solar_azimuth)
        pt_rad = math.radians(panel_tilt)
        pa_rad = math.radians(panel_azimuth)
        
        # Angle of incidence formula
        cos_incidence = (
            math.sin(se_rad) * math.cos(pt_rad) +
            math.cos(se_rad) * math.sin(pt_rad) * math.cos(sa_rad - pa_rad)
        )
        
        # For bifacial panels, allow light from angles > 90° but reduce efficiency
        if cos_incidence >= 0:
            return cos_incidence
        else:
            # Light from "behind" the panel surface - reduced efficiency
            return abs(cos_incidence) * 0.3  # 30% efficiency for oblique back-lighting
    
    def calculate_panel_irradiance(self, date, hour, minute, panel_tilt, panel_azimuth, panel_type='tilted'):
        """Calculate irradiance on panel surfaces with debugging"""
        solar_elev, solar_az = self.get_solar_position(date, hour, minute)
        
        print(f"\nPanel tilt {panel_tilt}°:")
        print(f"  Solar: elev={solar_elev:.1f}°, azim={solar_az:.1f}°")
        
        if solar_elev <= 0:
            return 0, 0  # No sun
        
        # Front side calculation (North-facing panels)
        front_cos = self.calculate_angle_of_incidence(solar_elev, solar_az, panel_tilt, panel_azimuth)
        
        # Back side calculation - bifacial panel has parallel surfaces
        back_azimuth = (panel_azimuth + 180) % 360
        back_cos = self.calculate_angle_of_incidence(solar_elev, solar_az, panel_tilt, back_azimuth)
        
        print(f"  Front cos_incidence: {front_cos:.4f}")
        print(f"  Back cos_incidence: {back_cos:.4f}")
        
        # Direct irradiance on surfaces
        front_direct = self.dni_clear_sky * front_cos if front_cos > 0 else 0
        back_direct = self.dni_clear_sky * back_cos if back_cos > 0 else 0
        
        print(f"  Front direct: {front_direct:.1f} W/m²")
        print(f"  Back direct: {back_direct:.1f} W/m²")
        
        # Diffuse irradiance (sky radiation)
        diffuse_factor = 0.15  # 15% of total radiation is diffuse
        sky_diffuse = self.dni_clear_sky * diffuse_factor
        
        front_diffuse = sky_diffuse * (1 + math.cos(math.radians(panel_tilt))) / 2
        back_diffuse = sky_diffuse * (1 - math.cos(math.radians(panel_tilt))) / 2
        
        print(f"  Front diffuse: {front_diffuse:.1f} W/m²")
        print(f"  Back diffuse: {back_diffuse:.1f} W/m²")
        
        # Ground reflected irradiance
        ground_reflected = self.dni_clear_sky * math.sin(math.radians(solar_elev)) * self.ground_albedo
        front_ground = ground_reflected * (1 - math.cos(math.radians(panel_tilt))) / 2 if front_cos > 0 else 0
        back_ground = ground_reflected * (1 + math.cos(math.radians(panel_tilt))) / 2 if back_cos > 0 else 0
        
        print(f"  Front ground: {front_ground:.1f} W/m²")
        print(f"  Back ground: {back_ground:.1f} W/m²")
        
        # Total irradiance
        front_irradiance = front_direct + front_diffuse + front_ground
        back_irradiance = (back_direct + back_diffuse + back_ground) * self.bifaciality_factor
        
        print(f"  Front total: {front_irradiance:.1f} W/m²")
        print(f"  Back total: {back_irradiance:.1f} W/m²")
        print(f"  Combined: {front_irradiance + back_irradiance:.1f} W/m²")
        
        total_irradiance = front_irradiance + back_irradiance
        power = (total_irradiance / 1000) * self.panel_power
        print(f"  Power: {power:.1f} W")
        
        return front_irradiance, back_irradiance

# Test pro říjen 14:00
debug_sim = DebugSolarSimulation()
date = datetime(2024, 10, 15)
hour = 14
minute = 0

print("=== Debug: October 15th, 14:00 ===")

# Test pro tilty 20° a 30°
for tilt in [20, 30]:
    debug_sim.calculate_panel_irradiance(date, hour, minute, tilt, 0, 'tilted')
    print()