#!/usr/bin/env python3
"""
Object-Oriented Traffic Light Controller
========================================
A class-based approach for scalable traffic light control.
Demonstrates software engineering best practices.

This approach is ideal for:
- Complex intersections
- Systems requiring logging or monitoring
- Integration with sensors or external control
- Testing and maintenance

Author: Educational demonstration
"""

from gpiozero import TrafficLights
from time import sleep
from enum import Enum
from typing import List
import logging

# Set up logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

class LightState(Enum):
    """Enumeration of possible traffic light states."""
    RED = "red"
    RED_AMBER = "red_amber"
    GREEN = "green"
    AMBER = "amber"
    OFF = "off"

class TrafficLightController:
    """
    Represents a single set of traffic lights with control logic.
    """
    
    def __init__(self, name: str, red_pin: int, amber_pin: int, green_pin: int):
        """
        Initialize a traffic light controller.
        
        Args:
            name: Descriptive name for this light set
            red_pin: GPIO pin number for red light
            amber_pin: GPIO pin number for amber light
            green_pin: GPIO pin number for green light
        """
        self.name = name
        self.lights = TrafficLights(red_pin, amber_pin, green_pin)
        self._current_state = LightState.OFF
        logging.info(f"Initialized {name} on pins R:{red_pin} A:{amber_pin} G:{green_pin}")
    
    @property
    def current_state(self) -> LightState:
        """Get the current state of the traffic light."""
        return self._current_state
    
    def set_state(self, state: LightState) -> None:
        """
        Set the traffic light to a specific state.
        
        Args:
            state: LightState enum value
        """
        if state == LightState.RED:
            self.lights.red.on()
            self.lights.amber.off()
            self.lights.green.off()
        elif state == LightState.RED_AMBER:
            self.lights.red.on()
            self.lights.amber.on()
            self.lights.green.off()
        elif state == LightState.GREEN:
            self.lights.red.off()
            self.lights.amber.off()
            self.lights.green.on()
        elif state == LightState.AMBER:
            self.lights.red.off()
            self.lights.amber.on()
            self.lights.green.off()
        elif state == LightState.OFF:
            self.lights.off()
        
        self._current_state = state
        logging.debug(f"{self.name} -> {state.value}")
    
    def turn_off(self) -> None:
        """Turn off all lights."""
        self.set_state(LightState.OFF)

class IntersectionController:
    """
    Controls a multi-way intersection with multiple traffic light sets.
    """
    
    def __init__(self, name: str):
        """
        Initialize the intersection controller.
        
        Args:
            name: Descriptive name for the intersection
        """
        self.name = name
        self.lights: List[TrafficLightController] = []
        self.is_running = False
        logging.info(f"Initialized intersection: {name}")
    
    def add_light(self, controller: TrafficLightController) -> None:
        """
        Add a traffic light controller to this intersection.
        
        Args:
            controller: TrafficLightController instance
        """
        self.lights.append(controller)
        logging.info(f"Added {controller.name} to {self.name}")
    
    def set_all_red(self) -> None:
        """Set all lights to red (safety state)."""
        for light in self.lights:
            light.set_state(LightState.RED)
        logging.info("All lights RED (safety state)")
    
    def shutdown(self) -> None:
        """Safely shutdown the intersection."""
        logging.info("Shutting down intersection...")
        self.is_running = False
        for light in self.lights:
            light.turn_off()
        logging.info("All lights OFF")

class TwoWayIntersection(IntersectionController):
    """
    Specialized controller for a two-way intersection.
    """
    
    def __init__(self, name: str, 
                 light_a: TrafficLightController,
                 light_b: TrafficLightController):
        """
        Initialize a two-way intersection.
        
        Args:
            name: Intersection name
            light_a: First direction controller
            light_b: Second direction controller
        """
        super().__init__(name)
        self.light_a = light_a
        self.light_b = light_b
        self.add_light(light_a)
        self.add_light(light_b)
    
    def give_priority_to(self, priority_light: TrafficLightController,
                         other_light: TrafficLightController,
                         green_time: int = 10) -> None:
        """
        Give priority (green light) to one direction.
        
        Args:
            priority_light: Light to give green
            other_light: Light to keep red
            green_time: Duration of green phase in seconds
        """
        # Red+Amber phase
        priority_light.set_state(LightState.RED_AMBER)
        other_light.set_state(LightState.RED)
        sleep(2)
        
        # Green phase
        priority_light.set_state(LightState.GREEN)
        other_light.set_state(LightState.RED)
        sleep(green_time)
        
        # Amber phase
        priority_light.set_state(LightState.AMBER)
        other_light.set_state(LightState.RED)
        sleep(3)
        
        # Safety buffer (all red)
        self.set_all_red()
        sleep(2)
    
    def run_cycle(self) -> None:
        """
        Run one complete cycle of the intersection.
        """
        logging.info(f"Starting cycle for {self.name}")
        
        # Direction A gets priority
        logging.info(f"{self.light_a.name} getting priority")
        self.give_priority_to(self.light_a, self.light_b)
        
        # Direction B gets priority
        logging.info(f"{self.light_b.name} getting priority")
        self.give_priority_to(self.light_b, self.light_a)
        
        logging.info("Cycle complete")
    
    def run(self) -> None:
        """
        Run the intersection controller continuously.
        """
        self.is_running = True
        self.set_all_red()
        sleep(2)
        
        try:
            while self.is_running:
                self.run_cycle()
        except KeyboardInterrupt:
            logging.info("Received interrupt signal")
            self.shutdown()

class ThreeWayIntersection(IntersectionController):
    """
    Specialized controller for a three-way T-junction.
    """
    
    def __init__(self, name: str,
                 main_road_a: TrafficLightController,
                 main_road_b: TrafficLightController,
                 side_road: TrafficLightController):
        """
        Initialize a three-way intersection.
        
        Args:
            name: Intersection name
            main_road_a: Main road direction A
            main_road_b: Main road direction B
            side_road: Side road controller
        """
        super().__init__(name)
        self.main_road_a = main_road_a
        self.main_road_b = main_road_b
        self.side_road = side_road
        self.add_light(main_road_a)
        self.add_light(main_road_b)
        self.add_light(side_road)
    
    def run_cycle(self) -> None:
        """
        Run one complete cycle of the T-junction.
        Main road (A+B paired) gets priority, then side road.
        """
        logging.info(f"Starting cycle for {self.name}")
        
        # Main road gets priority
        logging.info("Main road getting priority")
        
        # Red+Amber
        self.main_road_a.set_state(LightState.RED_AMBER)
        self.main_road_b.set_state(LightState.RED_AMBER)
        self.side_road.set_state(LightState.RED)
        sleep(2)
        
        # Green
        self.main_road_a.set_state(LightState.GREEN)
        self.main_road_b.set_state(LightState.GREEN)
        self.side_road.set_state(LightState.RED)
        sleep(12)  # Main road gets more time
        
        # Amber
        self.main_road_a.set_state(LightState.AMBER)
        self.main_road_b.set_state(LightState.AMBER)
        self.side_road.set_state(LightState.RED)
        sleep(3)
        
        # All red
        self.set_all_red()
        sleep(2)
        
        # Side road gets priority
        logging.info("Side road getting priority")
        
        # Red+Amber
        self.main_road_a.set_state(LightState.RED)
        self.main_road_b.set_state(LightState.RED)
        self.side_road.set_state(LightState.RED_AMBER)
        sleep(2)
        
        # Green
        self.main_road_a.set_state(LightState.RED)
        self.main_road_b.set_state(LightState.RED)
        self.side_road.set_state(LightState.GREEN)
        sleep(8)  # Side road gets less time
        
        # Amber
        self.main_road_a.set_state(LightState.RED)
        self.main_road_b.set_state(LightState.RED)
        self.side_road.set_state(LightState.AMBER)
        sleep(3)
        
        # All red
        self.set_all_red()
        sleep(2)
        
        logging.info("Cycle complete")
    
    def run(self) -> None:
        """
        Run the intersection controller continuously.
        """
        self.is_running = True
        self.set_all_red()
        sleep(2)
        
        try:
            while self.is_running:
                self.run_cycle()
        except KeyboardInterrupt:
            logging.info("Received interrupt signal")
            self.shutdown()

def demo_two_way():
    """
    Demonstration of two-way intersection control.
    """
    print("Two-Way Intersection Demo (Object-Oriented)")
    print("=" * 50)
    
    # Create traffic light controllers
    light_a = TrafficLightController("North-South", 2, 3, 4)
    light_b = TrafficLightController("East-West", 17, 27, 22)
    
    # Create intersection controller
    intersection = TwoWayIntersection("Main Crossroads", light_a, light_b)
    
    # Run the intersection
    print("Starting intersection control...")
    print("Press Ctrl+C to stop")
    intersection.run()

def demo_three_way():
    """
    Demonstration of three-way intersection control.
    """
    print("Three-Way Intersection Demo (Object-Oriented)")
    print("=" * 50)
    
    # Create traffic light controllers
    light_a = TrafficLightController("Main North", 2, 3, 4)
    light_b = TrafficLightController("Main South", 17, 27, 22)
    light_c = TrafficLightController("Side Road", 10, 9, 11)
    
    # Create intersection controller
    intersection = ThreeWayIntersection("T-Junction", light_a, light_b, light_c)
    
    # Run the intersection
    print("Starting intersection control...")
    print("Press Ctrl+C to stop")
    intersection.run()

if __name__ == "__main__":
    import sys
    
    if len(sys.argv) > 1 and sys.argv[1] == "three":
        demo_three_way()
    else:
        demo_two_way()
