from typing import Any
import logging
import httpx

from app.config import ServerConfiguration
from app.wsmesssages import *

logger = logging.getLogger(__name__)

class RequestProcessor:
    def __init__(self, config:ServerConfiguration):
        self.auto_url = f"{config.server.protocol}://localhost:{config.server.port}/api/v1/"
        pass

    async def process_request(self, request:dict[str, Any]) -> dict[str, Any] | list[dict[str, Any]] | None:

        # logger.info(f"Processing request: {request}")

        response: dict[str, Any] | list[dict[str, Any]] | None = None

        id = request.get("id")        
        if not id:            
            return response
        
        if id == "ping":
            response = {"id": "pong"}
            
        elif id == "version":
            response = {"id": "version", "version": "1.0.0"}
            
        elif id == GetFaceRecognitionStatusCmd.id:
            msg = GetFaceRecognitionStatusCmd(request)
            if not msg.isvalid:
                # logger.warning(f"Invalid getFaceRecogStatus request: {request}")
                rep = GetFaceRecognitionStatusResponse(
                    camera=msg.camera or "",
                    stream_url=msg.stream_url or "",
                    facerecog_status="unknown",
                    status="error",
                    message="Missing parameters for getFaceRecogStatus request"
                )
                return rep.toDict
            # Faire une requete HTTP à l'endpoint de reconnaissance faciale pour obtenir le statut
            req_url = f"{self.auto_url}facerecog/status"
            payload:dict[str, Any] = {
                "camera": msg.camera,
                "url": msg.stream_url
            }
            #logger.info(f"Sending request to face recognition service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    # logger.error(f"Error response from face recognition service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = GetFaceRecognitionStatusResponse(
                        camera=msg.camera or "",
                        stream_url=msg.stream_url or "",
                        facerecog_status="unknown",
                        status="error",
                        message=postrep.text
                    )
                    return rep.toDict
                postrep = postrep.json()
                url = postrep.get("url", None)
                camera = postrep.get("camera", None)
                status = postrep.get("status", None)
                #logger.info(f"Received status response from face recognition service: url={url}, camera={camera}, status={status}")
                rep = GetFaceRecognitionStatusResponse(
                    camera=camera or "",
                    stream_url=url or "",
                    facerecog_status=status or "unknown",
                    status="success",
                    message=""
                )
                response = rep.toDict
                
        elif id == StartFaceRecogCmd.id:
            msg = StartFaceRecogCmd(request)
            if not msg.isvalid:
                #logger.warning(f"Invalid startFaceRecog request: {request}")
                rep = StartFaceRecogResponse(
                    camera=msg.camera or "",
                    stream_url=msg.stream_url or "",
                    status="error",
                    message="Missing parameters for startFaceRecog request",
                    detector=msg.detector or ""
                )
                return rep.toDict
            # Faire une requete HTTP à l'endpoint de reconnaissance faciale pour démarrer la reconnaissance
            req_url = f"{self.auto_url}facerecog/start"
            payload:dict[str, Any] = {
                "camera": msg.camera,
                "url": msg.stream_url,
                "detector": msg.detector
            }
            # logger.info(f"Sending request to face recognition service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    #logger.error(f"Error response from face recognition service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = StartFaceRecogResponse(
                        camera=msg.camera or "",
                        stream_url=msg.stream_url or "",
                        status="error",
                        message=postrep.text,
                        detector=msg.detector or ""
                    )
                    return rep.toDict
                postrep = postrep.json()
                url = postrep.get("url", None)
                camera = postrep.get("camera", None)
                status = postrep.get("status", None)
                message = postrep.get("message", None)
                detector = postrep.get("detector", None)
                #logger.info(f"Received start response from face recognition service: url={url}, camera={camera}, status={status}, message={message}, detector={detector}")
                rep = StartFaceRecogResponse(
                    camera=camera or "",
                    stream_url=url or "",
                    status=status or "unknown",
                    message=message or "",
                    detector=detector or ""
                )
                response = rep.toDict

        elif id == StopFaceRecogCmd.id:
            msg = StopFaceRecogCmd(request)
            if not msg.isvalid:
                # logger.warning(f"Invalid stopFaceRecog request: {request}")
                rep = StopFaceRecogResponse(
                    camera=msg.camera or "",
                    stream_url=msg.stream_url or "",
                    status="error",
                    message="Missing parameters for stopFaceRecog request"
                )
                return rep.toDict
            # Faire une requete HTTP à l'endpoint de reconnaissance faciale pour arrêter la reconnaissance
            req_url = f"{self.auto_url}facerecog/stop"
            payload:dict[str, Any] = {
                "url": msg.stream_url,
                "camera": msg.camera
            }
            # logger.info(f"Sending request to face recognition service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    # logger.error(f"Error response from face recognition service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = StopFaceRecogResponse(
                        camera=msg.camera or "",
                        stream_url=msg.stream_url or "",
                        status="error",
                        message=postrep.text
                    )
                    return rep.toDict
                postrep = postrep.json()
                url = postrep.get("url", None)
                camera = postrep.get("camera", None)
                status = postrep.get("status", None)
                message = postrep.get("message", None)
                # logger.info(f"Received stop response from face recognition service: url={url}, camera={camera}, status={status}, message={message}")
                rep = StopFaceRecogResponse(
                    camera=camera or "",
                    stream_url=url or "",
                    status=status or "unknown",
                    message=message or ""
                )
                response = rep.toDict
                
        elif id == GetCameraStatusCmd.id:
            msg = GetCameraStatusCmd(request)
            if not msg.isvalid:
                # logger.warning(f"Invalid getCameraStatus request: {request}")
                rep = CameraStatusResponse(
                    camera=msg.camera or "",
                    network=msg.network or "",
                    on_air=False,
                    preview=False,
                    status="error",
                    message="Missing parameters for getCameraStatus request"
                )
                return rep.toDict
            req_url = f"{self.auto_url}cameras/status"
            payload:dict[str, Any] = {
                "network": msg.network,
                "camera": msg.camera
            }
            # logger.info(f"Sending request to camera service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    # logger.error(f"Error response from camera service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = CameraStatusResponse(
                        camera=msg.camera or "",
                        network=msg.network or "",
                        on_air=False,
                        preview=False,
                        status="error",
                        message=postrep.text
                    )
                    return rep.toDict
                postrep = postrep.json()
                camera = postrep.get("camera", None)
                network = postrep.get("network", None)
                on_air = postrep.get("on_air", False)
                preview = postrep.get("preview", False)
                rep = CameraStatusResponse(
                    camera=camera or "",
                    network=network or "",
                    on_air=on_air,
                    preview=preview,
                    status="success",
                    message=""
                )
                response = rep.toDict
        
        elif id == SetCameraOnAirCmd.id:
            msg = SetCameraOnAirCmd(request)
            if not msg.isvalid:
                # logger.warning(f"Invalid getCameraStatus request: {request}")
                rep = CameraStatusResponse(
                    camera=msg.camera or "",
                    network=msg.network or "",
                    on_air=False,
                    preview=False,
                    status="error",
                    message="Missing parameters for getCameraStatus request"
                )
                return rep.toDict
            req_url = f"{self.auto_url}cameras/setonair"
            payload:dict[str, Any] = {
                "camera": msg.camera,
                "network": msg.network,
                "on_air": msg.on_air,
            }
            # logger.info(f"Sending request to camera service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    # logger.error(f"Error response from camera service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = CameraStatusResponse(
                        camera=msg.camera or "",
                        network=msg.network or "",
                        on_air=False,
                        preview=False,
                        status="error",
                        message=postrep.text
                    )
                    return rep.toDict
                postrep = postrep.json()
                camera = postrep.get("camera", None)
                network = postrep.get("network", None)
                on_air = postrep.get("on_air", False)
                preview = postrep.get("preview", False)
                rep = CameraStatusResponse(
                    camera=camera or "",
                    network=network or "",
                    on_air=on_air,
                    preview=preview,
                    status="success",
                    message=""
                )
                reps = [rep.toDict]
                other_cams:list[dict[str, Any]] = postrep.get("other_cams", [])
                for c in other_cams:
                    rep = CameraStatusResponse(
                        camera=c.get("camera", ""),
                        network=network,
                        on_air=c.get("on_air", False),
                        preview=c.get("preview", False),
                        status="success",
                        message=""
                    )
                    reps.append(rep.toDict)
                response = reps

        elif id == SetCameraPreviewCmd.id:
            msg = SetCameraPreviewCmd(request)
            if not msg.isvalid:
                # logger.warning(f"Invalid getCameraStatus request: {request}")
                rep = CameraStatusResponse(
                    camera=msg.camera or "",
                    network=msg.network or "",
                    on_air=False,
                    preview=False,
                    status="error",
                    message="Missing parameters for getCameraStatus request"
                )
                return rep.toDict
            req_url = f"{self.auto_url}cameras/setpreview"
            payload:dict[str, Any] = {
                "camera": msg.camera,
                "network": msg.network,
                "preview": msg.preview,
            }
            # logger.info(f"Sending request to camera service to url {req_url}: {payload}")
            async with httpx.AsyncClient() as client:
                postrep = await client.post(req_url, json=payload)
                if (postrep.status_code != 200):
                    # logger.error(f"Error response from camera service: status_code={postrep.status_code}, content={postrep.text}")
                    rep = CameraStatusResponse(
                        camera=msg.camera or "",
                        network=msg.network or "",
                        on_air=False,
                        preview=False,
                        status="error",
                        message=postrep.text
                    )
                    return rep.toDict
                postrep = postrep.json()
                camera = postrep.get("camera", None)
                network = postrep.get("network", None)
                on_air = postrep.get("on_air", False)
                preview = postrep.get("preview", False)
                rep = CameraStatusResponse(
                    camera=camera or "",
                    network=network or "",
                    on_air=on_air,
                    preview=preview,
                    status="success",
                    message=""
                )
                reps = [rep.toDict]
                other_cams:list[dict[str, Any]] = postrep.get("other_cams", [])
                for c in other_cams:
                    rep = CameraStatusResponse(
                        camera=c.get("camera", ""),
                        network=network or "",
                        on_air=c.get("on_air", False),
                        preview=c.get("preview", False),
                        status="success",
                        message=""
                    )
                    reps.append(rep.toDict)
                response = reps

        else:
            logger.warning(f"Unknown request id: {id}")

        return response
    