"""
Camera module for ESP32-CAM stream capture
"""

import cv2
import numpy as np
import requests
import time
from typing import Optional, Tuple


class ESP32Camera:
    """
    Captures frames from ESP32-CAM HTTP stream
    """
    
    def __init__(self, url: str, timeout: int = 5):
        """
        Initialize camera stream
        
        Args:
            url: ESP32-CAM stream URL (e.g., http://192.168.1.100/cam-mid.jpg)
            timeout: HTTP request timeout in seconds
        """
        self.url = url
        self.timeout = timeout
        self.last_frame = None
        self.last_capture_time = 0
        self.frame_count = 0
        self.error_count = 0
        
        # Test connection
        if not self._test_connection():
            raise ConnectionError(f"Cannot connect to camera at {url}")
        
    def _test_connection(self) -> bool:
        """Test if camera is accessible"""
        try:
            response = requests.get(self.url, timeout=2)
            return response.status_code == 200
        except:
            return False
    
    def capture(self) -> Optional[np.ndarray]:
        """
        Capture a single frame from the camera
        
        Returns:
            numpy array (BGR image) or None if capture fails
        """
        try:
            response = requests.get(self.url, timeout=self.timeout)
            
            if response.status_code != 200:
                self.error_count += 1
                return self.last_frame  # Return last good frame
            
            # Convert response to numpy array
            img_array = np.array(bytearray(response.content), dtype=np.uint8)
            frame = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
            
            if frame is not None:
                self.last_frame = frame
                self.frame_count += 1
                self.last_capture_time = time.time()
                self.error_count = 0
                
            return frame
            
        except Exception as e:
            self.error_count += 1
            print(f"Camera capture error: {e}")
            return self.last_frame  # Return last good frame
    
    def get_stats(self) -> dict:
        """Get camera statistics"""
        return {
            'frames_captured': self.frame_count,
            'errors': self.error_count,
            'last_capture': self.last_capture_time,
            'url': self.url
        }
    
    def __del__(self):
        """Cleanup"""
        pass


class FPSCounter:
    """
    Calculate frames per second
    """
    
    def __init__(self, buffer_size: int = 30):
        """
        Args:
            buffer_size: Number of frames to average over
        """
        self.buffer_size = buffer_size
        self.timestamps = []
        
    def update(self):
        """Update with current timestamp"""
        now = time.time()
        self.timestamps.append(now)
        
        # Keep only recent timestamps
        if len(self.timestamps) > self.buffer_size:
            self.timestamps.pop(0)
    
    def get_fps(self) -> float:
        """
        Calculate current FPS
        
        Returns:
            FPS as float, or 0.0 if not enough data
        """
        if len(self.timestamps) < 2:
            return 0.0
        
        time_diff = self.timestamps[-1] - self.timestamps[0]
        if time_diff == 0:
            return 0.0
        
        return (len(self.timestamps) - 1) / time_diff


# Test code
if __name__ == "__main__":
    import sys
    
    if len(sys.argv) < 2:
        print("Usage: python3 camera.py <camera_url>")
        print("Example: python3 camera.py http://192.168.1.100/cam-mid.jpg")
        sys.exit(1)
    
    url = sys.argv[1]
    
    print(f"Testing camera at: {url}")
    
    try:
        camera = ESP32Camera(url)
        fps_counter = FPSCounter()
        
        print("Camera connected. Press 'q' to quit.")
        
        while True:
            frame = camera.capture()
            
            if frame is not None:
                fps_counter.update()
                fps = fps_counter.get_fps()
                
                # Draw FPS on frame
                cv2.putText(frame, f"FPS: {fps:.1f}", (10, 30),
                           cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                
                cv2.imshow('ESP32-CAM Test', frame)
                
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break
            else:
                print("Frame capture failed")
                time.sleep(0.1)
        
        print("\nCamera stats:")
        print(camera.get_stats())
        
        cv2.destroyAllWindows()
        
    except Exception as e:
        print(f"Error: {e}")
        sys.exit(1)
