#!/usr/bin/env python3
"""
Saskatchewan HVAC Route Analysis Tool
Analyzes HVAC service routes for optimal scheduling and costing
"""

from dataclasses import dataclass

# Constants
MILES_TO_KM = 1.60934
AVG_SPEED_KMH = 80  # Average rural highway speed in SK
SITE_VISIT_HOURS = 2.5
REGULAR_HOURS = 8
MAX_HOURS = 12
OVERTIME_MULTIPLIER = 1.5
ROUTES_PER_YEAR = 2

# Parse Book 4 - Route details (distances in miles between legs)
routes_data = """
Route,Sites,Leg_Distances_Miles,Total_Miles
Regina - Local,"Lumsden, Regina ReStore, Regina Butterfield","20,21,2,0",43
Regina - N,"Bulyea, Strasbourg, Nokomis, Jansen","44,8,31,40,112",236
Regina - W,"Moose Jaw, Swift Current","48,111,153",312
Regina - YQV,"Yorkton","115,115",230
S'toon - Local,"Saskatoon LINN, Saskatoon Old TT, Casa Rio","1,5,11,14",31
S'toon - NE,"Humboldt, Tarnopol, Prud'Homme","70,45,48,40",203
S'toon - PA,"Neuanlage, Rosthern, Prince Albert, Waldheim","23,17,47,63,34",184
S'toon - SE,"Clavet, Allan, Young, Shields, Cardinal Estates","25,17,15,31,11,22",122
"""

@dataclass
class Route:
    name: str
    branch: str
    sites: list
    leg_distances_miles: list
    total_miles: float

    @property
    def total_km(self) -> float:
        return self.total_miles * MILES_TO_KM

    @property
    def num_sites(self) -> int:
        return len(self.sites)

    @property
    def driving_hours(self) -> float:
        return self.total_km / AVG_SPEED_KMH

    @property
    def site_work_hours(self) -> float:
        return self.num_sites * SITE_VISIT_HOURS

    @property
    def total_hours(self) -> float:
        return self.driving_hours + self.site_work_hours

    @property
    def overtime_hours(self) -> float:
        return max(0, self.total_hours - REGULAR_HOURS)

    @property
    def regular_hours(self) -> float:
        return min(self.total_hours, REGULAR_HOURS)

# Build route objects
routes = [
    Route("Regina - Local", "Regina",
          ["Lumsden", "Regina ReStore", "Regina Butterfield"],
          [20, 21, 2, 0], 43),
    Route("Regina - N", "Regina",
          ["Bulyea", "Strasbourg", "Nokomis", "Jansen"],
          [44, 8, 31, 40, 112], 236),
    Route("Regina - W", "Regina",
          ["Moose Jaw", "Swift Current"],
          [48, 111, 153], 312),
    Route("Regina - YQV", "Regina",
          ["Yorkton"],
          [115, 115], 230),
    Route("S'toon - Local", "Saskatoon",
          ["Saskatoon LINN", "Saskatoon Old TT", "Casa Rio"],
          [1, 5, 11, 14], 31),
    Route("S'toon - NE", "Saskatoon",
          ["Humboldt", "Tarnopol", "Prud'Homme"],
          [70, 45, 48, 40], 203),
    Route("S'toon - PA", "Saskatoon",
          ["Neuanlage", "Rosthern", "Prince Albert", "Waldheim"],
          [23, 17, 47, 63, 34], 184),
    Route("S'toon - SE", "Saskatoon",
          ["Clavet", "Allan", "Young", "Shields", "Cardinal Estates"],
          [25, 17, 15, 31, 11, 22], 122),
]

print("=" * 80)
print("SASKATCHEWAN HVAC SERVICE ROUTE ANALYSIS")
print("=" * 80)
print()
print(f"Assumptions:")
print(f"  - Average driving speed: {AVG_SPEED_KMH} km/h")
print(f"  - Time per site visit: {SITE_VISIT_HOURS} hours")
print(f"  - Regular workday: {REGULAR_HOURS} hours")
print(f"  - Maximum workday: {MAX_HOURS} hours")
print(f"  - Overtime multiplier: {OVERTIME_MULTIPLIER}x")
print(f"  - Routes per year: {ROUTES_PER_YEAR}")
print()

# Summary by route
print("=" * 80)
print("ROUTE-BY-ROUTE ANALYSIS")
print("=" * 80)
print()

total_sites = 0
total_km = 0
total_hours = 0
total_regular = 0
total_overtime = 0

for route in routes:
    total_sites += route.num_sites
    total_km += route.total_km
    total_hours += route.total_hours
    total_regular += route.regular_hours
    total_overtime += route.overtime_hours

    status = "✓ OK" if route.total_hours <= MAX_HOURS else "⚠ OVER MAX"
    ot_warning = f" (OT: {route.overtime_hours:.1f}h)" if route.overtime_hours > 0 else ""

    print(f"ROUTE: {route.name}")
    print(f"  Branch: {route.branch}")
    print(f"  Sites: {route.num_sites} - {', '.join(route.sites)}")
    print(f"  Distance: {route.total_miles} mi / {route.total_km:.0f} km")
    print(f"  Driving time: {route.driving_hours:.1f} hours")
    print(f"  Site work: {route.site_work_hours:.1f} hours")
    print(f"  TOTAL TIME: {route.total_hours:.1f} hours {status}{ot_warning}")
    print()

# Summary by branch
print("=" * 80)
print("BRANCH SUMMARY")
print("=" * 80)
print()

for branch in ["Regina", "Saskatoon"]:
    branch_routes = [r for r in routes if r.branch == branch]
    branch_sites = sum(r.num_sites for r in branch_routes)
    branch_km = sum(r.total_km for r in branch_routes)
    branch_hours = sum(r.total_hours for r in branch_routes)
    branch_regular = sum(r.regular_hours for r in branch_routes)
    branch_overtime = sum(r.overtime_hours for r in branch_routes)
    branch_days = len(branch_routes)

    print(f"{branch.upper()} BRANCH:")
    print(f"  Routes: {branch_days}")
    print(f"  Sites: {branch_sites}")
    print(f"  Total distance: {branch_km:.0f} km")
    print(f"  Total time: {branch_hours:.1f} hours")
    print(f"  Regular hours: {branch_regular:.1f}")
    print(f"  Overtime hours: {branch_overtime:.1f}")
    print()

# Overall summary
print("=" * 80)
print("OVERALL SUMMARY (PER ROUTE CYCLE)")
print("=" * 80)
print()
print(f"Total sites: {total_sites}")
print(f"Total routes/days: {len(routes)}")
print(f"Total distance: {total_km:.0f} km ({total_km/MILES_TO_KM:.0f} miles)")
print(f"Total time: {total_hours:.1f} hours")
print(f"  - Regular hours: {total_regular:.1f}")
print(f"  - Overtime hours: {total_overtime:.1f}")
print()

# Per-year calculations
print("=" * 80)
print("ANNUAL SUMMARY (2 routes per year)")
print("=" * 80)
print()
print(f"Total site visits/year: {total_sites * ROUTES_PER_YEAR}")
print(f"Total km driven/year: {total_km * ROUTES_PER_YEAR:.0f} km")
print(f"Total labour hours/year: {total_hours * ROUTES_PER_YEAR:.1f}")
print(f"  - Regular hours: {total_regular * ROUTES_PER_YEAR:.1f}")
print(f"  - Overtime hours: {total_overtime * ROUTES_PER_YEAR:.1f}")
print()

# Cost model example
print("=" * 80)
print("COST MODELING (Example rates - adjust as needed)")
print("=" * 80)
print()

# Example rates - user should adjust
HOURLY_RATE = 75  # Base hourly rate for technician
VEHICLE_COST_PER_KM = 0.65  # Fuel + wear

regular_cost = total_regular * HOURLY_RATE
overtime_cost = total_overtime * HOURLY_RATE * OVERTIME_MULTIPLIER
vehicle_cost = total_km * VEHICLE_COST_PER_KM
total_cost_per_cycle = regular_cost + overtime_cost + vehicle_cost

print(f"Example hourly rate: ${HOURLY_RATE}/hr")
print(f"Vehicle cost: ${VEHICLE_COST_PER_KM}/km")
print()
print(f"Per route cycle:")
print(f"  Regular labour: ${regular_cost:.2f}")
print(f"  Overtime labour: ${overtime_cost:.2f}")
print(f"  Vehicle costs: ${vehicle_cost:.2f}")
print(f"  TOTAL: ${total_cost_per_cycle:.2f}")
print()
print(f"Annual (x{ROUTES_PER_YEAR}):")
print(f"  Regular labour: ${regular_cost * ROUTES_PER_YEAR:.2f}")
print(f"  Overtime labour: ${overtime_cost * ROUTES_PER_YEAR:.2f}")
print(f"  Vehicle costs: ${vehicle_cost * ROUTES_PER_YEAR:.2f}")
print(f"  TOTAL: ${total_cost_per_cycle * ROUTES_PER_YEAR:.2f}")
print()

# Identify problem routes
print("=" * 80)
print("ROUTE CONCERNS")
print("=" * 80)
print()

over_max = [r for r in routes if r.total_hours > MAX_HOURS]
heavy_ot = [r for r in routes if r.overtime_hours > 2]

if over_max:
    print("ROUTES EXCEEDING 12-HOUR MAX:")
    for r in over_max:
        print(f"  - {r.name}: {r.total_hours:.1f} hours (need to split)")
else:
    print("✓ No routes exceed 12-hour maximum")
print()

if heavy_ot:
    print("ROUTES WITH SIGNIFICANT OVERTIME (>2 hours):")
    for r in heavy_ot:
        print(f"  - {r.name}: {r.overtime_hours:.1f} hours overtime")
else:
    print("✓ No routes with excessive overtime")
print()

# Optimization suggestions
print("=" * 80)
print("OPTIMIZATION SUGGESTIONS")
print("=" * 80)
print()

for route in routes:
    if route.total_hours > MAX_HOURS:
        print(f"❌ {route.name}: {route.total_hours:.1f}h - MUST BE SPLIT")
        print(f"   Consider breaking into {int(route.total_hours / 8) + 1} days")
    elif route.overtime_hours > 3:
        print(f"⚠ {route.name}: {route.total_hours:.1f}h - Consider splitting to reduce overtime")
    elif route.total_hours < 6:
        print(f"💡 {route.name}: {route.total_hours:.1f}h - Could potentially combine with nearby route")
    else:
        print(f"✓ {route.name}: {route.total_hours:.1f}h - Reasonable")
print()

# Per-site cost
print("=" * 80)
print("PER-SITE ECONOMICS")
print("=" * 80)
print()
cost_per_site = total_cost_per_cycle / total_sites
print(f"Average cost per site visit: ${cost_per_site:.2f}")
print(f"Average time per site (including travel): {total_hours / total_sites:.1f} hours")
print()
