from fastapi import APIRouter, Request
from api.common import api_response, api_abort, api_ok, validate
from api.command_helpers import enqueue_tx_command
import command_cq
import command_beacon
import command_ping
import command_fec
import command_test
import command_arq_raw
import api_validations as validations

router = APIRouter()


@router.get("/state", summary="Get Modem State", tags=["Modem"], responses={
    200: {
        "description": "Current modem state information.",
        "content": {
            "application/json": {
                "example": {
                    "activities": {
                        "161dd75ef3b5847a": {
                            "activity_type": "ARQ_BURST_ACK",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "session_id": 105,
                            "snr": 4,
                            "timestamp": 1713034266
                        },
                        "168e90799d13b7b4": {
                            "activity_type": "ARQ_SESSION_INFO_ACK",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "session_id": 105,
                            "snr": -3,
                            "timestamp": 1713034248
                        },
                        "2218b849e937d36d": {
                            "activity_type": "QRV",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "gridsquare": "JP15OW",
                            "origin": "SOMECALL-1",
                            "snr": 2,
                            "timestamp": 1713034200
                        },
                        "3fb424827f4632ab": {
                            "activity_type": "BEACON",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "gridsquare": "JP22AI",
                            "origin": "CALLSIGN-1",
                            "snr": -8,
                            "timestamp": 1713034455
                        },
                        "743222d1dd64ce9d": {
                            "activity_type": "ARQ_SESSION_OPEN_ACK",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "origin": "CALL-1",
                            "session_id": 105,
                            "snr": -2,
                            "timestamp": 1713034243
                        },
                        "7589edf6bf23ceed": {
                            "activity_type": "ARQ_BURST_ACK",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "session_id": 105,
                            "snr": 2,
                            "timestamp": 1713034275
                        },
                        "9d2c5a98fe0f9894": {
                            "activity_type": "QRV",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "gridsquare": "JP12AW",
                            "origin": "CALLME-1",
                            "snr": 5,
                            "timestamp": 1713034178
                        },
                        "f85609dced4ea40a": {
                            "activity_type": "ARQ_BURST_ACK",
                            "direction": "received",
                            "frequency": "14093000",
                            "frequency_offset": 0,
                            "session_id": 105,
                            "snr": 0,
                            "timestamp": 1713034257
                        }
                    },
                    "audio_dbfs": -7.915304862713354,
                    "channel_busy_slot": [False, False, True, False, False],
                    "is_away_from_key": False,
                    "is_beacon_running": True,
                    "is_modem_busy": False,
                    "is_modem_running": True,
                    "radio_frequency": "14093000",
                    "radio_mode": "PKTUSB",
                    "radio_status": True,
                    "s_meter_strength": "20",
                    "type": "state"
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    }
})
async def get_modem_state(request:Request):
    """
    Retrieve the current state of the modem.

    Returns:
        dict: A JSON object containing modem state information.
    """
    return request.app.state_manager.sendState()


@router.post("/cqcqcq", summary="Send CQ Command", tags=["Modem"], responses={
    200: {
        "description": "CQ command sent successfully.",
        "content": {
            "application/json": {
                "example": {
                    "message": "ok"
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_cqcqcq(request:Request):
    """
    Trigger the modem to send a CQ.

    Returns:
        dict: A JSON object indicating success.

    Raises:
        HTTPException: If the modem is not running.
    """
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)
    await enqueue_tx_command(request.app, command_cq.CQCommand)
    return api_ok()


@router.post("/beacon", summary="Enable/Disable Modem Beacon", tags=["Modem"], responses={
    200: {
        "description": "Beacon status updated successfully.",
        "content": {
            "application/json": {
                "example": {
                    "enabled": True,
                    "away_from_key": False
                }
            }
        }
    },
    400: {
        "description": "Invalid input parameters.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Incorrect value for 'enabled' or 'away_from_key'. Should be bool."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_beacon(request: Request):
    """
    Enable or disable the modem beacon.

    Parameters:
        request (Request): The HTTP request containing the following JSON keys:
            - 'enabled' (bool): True to enable the beacon, False to disable.
            - 'away_from_key' (bool): True if away from key, False otherwise.

    Returns:
        dict: A JSON object indicating the beacon status.

    Raises:
        HTTPException: If parameters are invalid or modem is not running.
    """
    data = await request.json()
    if not isinstance(data.get('enabled'), bool) or not isinstance(data.get('away_from_key'), bool):
        api_abort("Incorrect value for 'enabled' or 'away_from_key'. Should be bool.", 400)
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)
    request.app.state_manager.set('is_beacon_running', data['enabled'])
    request.app.state_manager.set('is_away_from_key', data['away_from_key'])
    if not request.app.state_manager.getARQ() and data['enabled']:
        await enqueue_tx_command(request.app, command_beacon.BeaconCommand, data)
    return api_response({"enabled": data['enabled'], "away_from_key": data['away_from_key']})


@router.post("/ping_ping", summary="Trigger Modem to PING a Station", tags=["Modem"], responses={
    200: {
        "description": "Ping command sent successfully.",
        "content": {
            "application/json": {
                "example": {
                    "message": True
                }
            }
        }
    },
    400: {
        "description": "Invalid input parameters.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Invalid 'dxcall' parameter."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_ping(request: Request):
    """
    Trigger the modem to send a PING to a station.

    Parameters:
        request (Request): The HTTP request containing the following JSON key:
            - 'dxcall' (str): Callsign of the station to ping.

    Returns:
        dict: A JSON object indicating success.

    Raises:
        HTTPException: If parameters are invalid or modem is not running.
    """
    data = await request.json()
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)
    dxcall = data.get('dxcall')
    if not dxcall or not validations.validate_freedata_callsign(dxcall):
        api_abort("Invalid 'dxcall' parameter.", 400)
    await enqueue_tx_command(request.app, command_ping.PingCommand, data)
    return api_response({"message": True})


@router.post("/send_test_frame", summary="Send Test Frame", tags=["Modem"], responses={
    200: {
        "description": "Test frame sent successfully.",
        "content": {
            "application/json": {
                "example": {
                    "message": "ok"
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_send_test_frame(request:Request):
    """
    Trigger the modem to send a test frame.

    Returns:
        dict: A JSON object indicating success.

    Raises:
        HTTPException: If the modem is not running.
    """
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)
    await enqueue_tx_command(request.app, command_test.TestCommand)
    return api_ok()

@router.post("/fec_transmit", summary="FEC Transmit", tags=["Modem"], responses={
    200: {
        "description": "FEC frame transmitted successfully.",
        "content": {
            "application/json": {
                "example": {
                    "message": "FEC transmission started."
                }
            }
        }
    },
    400: {
        "description": "Bad Request: The request was malformed or missing required parameters.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Invalid parameters."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    500: {
        "description": "Internal Server Error: An unexpected error occurred on the server.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Internal server error."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_send_fec_frame(request: Request):
    """
    Trigger the modem to transmit a Forward Error Correction (FEC) frame.

    Parameters:
        request (Request): The HTTP request containing transmission parameters in JSON format.

    Returns:
        dict: A JSON object indicating success.

    Raises:
        HTTPException: If the modem is not running, the request is malformed, or an internal error occurs.
    """
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)

    try:
        data = await request.json()
    except Exception:
        api_abort("Invalid parameters.", 400)

    # Validate required parameters (adjust based on actual requirements)
    if 'message' not in data:
        api_abort("Invalid parameters: 'message' field is required.", 400)

    # Enqueue the FEC transmission command
    try:
        await enqueue_tx_command(request.app, command_fec.FecCommand, data)
        return api_response({"message": "FEC transmission started."})
    except Exception as e:
        # Log the exception if necessary
        api_abort("Internal server error.", 500)


from fastapi import HTTPException

@router.get("/fec_is_writing", summary="Indicate User is Typing (FEC)", tags=["Modem"], responses={
    501: {
        "description": "Feature not implemented.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Feature not implemented yet."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def get_fec_is_writing(request:Request):
    """
    Trigger the modem to inform over RF that the user is typing a message.

    Returns:
        dict: A JSON object indicating that the feature is not implemented.

    Raises:
        HTTPException: If the modem is not running or the feature is not implemented.
    """
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running", 503)

    # Since the feature is not implemented yet, return a 501 Not Implemented error
    raise HTTPException(status_code=501, detail="Feature not implemented yet.")


@router.post("/start", summary="Start Modem", tags=["Modem"], responses={
    200: {
        "description": "Modem started successfully.",
        "content": {
            "application/json": {
                "examples": {
                    "modem_started": {
                        "summary": "Modem Started",
                        "value": {
                            "modem": "started"
                        }
                    },
                    "message_ok": {
                        "summary": "Message OK",
                        "value": {
                            "message": "ok"
                        }
                    }
                }
            }
        }
    },
    400: {
        "description": "Bad Request: The request was malformed or missing required parameters.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Invalid parameters."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    500: {
        "description": "Internal Server Error: An unexpected error occurred on the server.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Internal server error."
                }
            }
        }
    }
})
async def post_modem_start(request: Request):
    """
    Trigger the modem to start.

    Parameters:
        request (Request): The HTTP request
    Returns:
        dict: A JSON object indicating the modem has started.

    Raises:
        HTTPException: If parameters are invalid or an error occurs.
    """

    try:
        if not request.app.state_manager.is_modem_running:
            request.app.modem_service.put("start")
            return api_response({"modem": "started"})
        else:
            api_abort("Modem already running", 503)
    except Exception as e:
        api_abort(f"Internal server error. {e}", 500)


@router.post("/stop", summary="Stop Modem", tags=["Modem"], responses={
    200: {
        "description": "Modem stopped successfully.",
        "content": {
            "application/json": {
                "examples": {
                    "modem_stopped": {
                        "summary": "Modem Stopped",
                        "value": {
                            "modem": "stopped"
                        }
                    },
                    "message_ok": {
                        "summary": "Message OK",
                        "value": {
                            "message": "ok"
                        }
                    }
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_modem_stop(request:Request):
    """
    Trigger the modem to stop.

    Returns:
        dict: A JSON object indicating the modem has stopped.

    Raises:
        HTTPException: If the modem is not running or an error occurs.
    """
    #if not request.app.state_manager.is_modem_running:
    #    api_abort("Modem not running", 503)

    try:
        request.app.modem_service.put("stop")
        return api_response({"modem": "stopped"})
    except Exception as e:
        api_abort(f"Internal server error. {e}", 500)



@router.post("/send_arq_raw", summary="Send ARQ Raw Data", tags=["Modem"], responses={
    200: {
        "description": "ARQ raw data sent successfully.",
        "content": {
            "application/json": {
                "example": {
                    "data": "RnJlZURBVEEgaXMgdGhlIGJlc3Qh",
                    "dxcall": "XX1XXX-6",
                    "type": "raw"
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    503: {
        "description": "Modem not running or busy.",
        "content": {
            "application/json": {
                "examples": {
                    "modem_not_running": {
                        "summary": "Modem Not Running",
                        "value": {
                            "error": "Modem not running."
                        }
                    },
                    "modem_busy": {
                        "summary": "Modem Busy",
                        "value": {
                            "error": "Modem Busy."
                        }
                    }
                }
            }
        }
    }
})
async def post_send_arq_raw(request: Request):
    """
    Send ARQ raw data to a specified station.

    Parameters:
        request (Request): The HTTP request containing the following JSON keys:
            - 'dxcall' (str): Callsign of the station to send data to.
            - 'type' (str): Data type ('raw', 'raw_lzma', 'raw_gzip').
            - 'data' (str): Base64 encoded data to send.

    Returns:
        dict: A JSON object echoing the sent data.

    Raises:
        HTTPException: If parameters are invalid or modem is not running/busy.
    """
    if not request.app.state_manager.is_modem_running:
        api_abort("Modem not running.", 503)
    if request.app.state_manager.is_modem_busy:
        api_abort("Modem Busy.", 503)
    data = await request.json()
    dxcall = data.get('dxcall')
    data_type = data.get('type')
    raw_data = data.get('data')
    if not dxcall or not validations.validate_freedata_callsign(dxcall):
        api_abort("Invalid 'dxcall' parameter.", 400)
    if data_type not in ['raw', 'raw_lzma', 'raw_gzip']:
        api_abort("Invalid 'type' parameter.", 400)
    if not raw_data:
        api_abort("Missing 'data' parameter.", 400)
    await enqueue_tx_command(request.app, command_arq_raw.SendARQRawCommand, data)
    return api_response({
        "data": raw_data,
        "dxcall": dxcall,
        "type": data_type
    })


@router.post("/stop_transmission", summary="Stop Transmission", tags=["Modem"], responses={
    200: {
        "description": "Transmission stopped successfully.",
        "content": {
            "application/json": {
                "example": {
                    "message": "ok"
                }
            }
        }
    },
    400: {
        "description": "Bad Request: The request was malformed or missing required parameters.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Invalid request."
                }
            }
        }
    },
    404: {
        "description": "The requested resource was not found.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Resource not found."
                }
            }
        }
    },
    500: {
        "description": "Internal Server Error: An unexpected error occurred on the server.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Internal server error."
                }
            }
        }
    },
    503: {
        "description": "Modem not running.",
        "content": {
            "application/json": {
                "example": {
                    "error": "Modem not running."
                }
            }
        }
    }
})
async def post_modem_stop_transmission(request:Request):
    """
    Stop the current transmission.

    Returns:
        dict: A JSON object indicating success.

    Raises:
        HTTPException: If the modem is not running or an error occurs.
    """
    try:
        request.app.state_manager.stop_transmission()
    except Exception as e:
        print(f"Error during transmission stopping: {e}")
    return api_ok()



