"""High frequency commands: hf.*"""
import struct
import asyncio
from .protocol import Cmd
from .transport import PM3Transport, PM3Error, ProgressCallback


class HFCommands:
    """High frequency commands."""

    def __init__(self, transport: PM3Transport):
        self._t = transport
        # Sub-modules attached by client.py
        self.a14 = None  # type: ignore
        self.iso15 = None  # type: ignore
        self.mf = None  # type: ignore

    async def tune(self, on_progress: ProgressCallback = None) -> dict:
        """Measure HF antenna voltage."""
        resp = await self._t.send_ng(Cmd.MEASURE_ANTENNA_TUNING_HF, timeout=10.0)
        voltage = struct.unpack_from("<I", resp.data, 0)[0] if len(resp.data) >= 4 else 0
        result = {
            "voltage_mV": voltage,
            "voltage_V": round(voltage / 1000.0, 3),
        }
        if on_progress:
            ret = on_progress({"type": "hf_tune", "result": result})
            if asyncio.iscoroutine(ret):
                await ret
        return result

    async def search(self, on_progress: ProgressCallback = None) -> dict:
        """Search for HF tags. Tries 14a, then 15."""
        results = {}

        if on_progress:
            ret = on_progress({"type": "hf_search", "phase": "14a"})
            if asyncio.iscoroutine(ret):
                await ret

        if self.a14:
            try:
                card = await self.a14.scan()
                if card.get("uid"):
                    results["iso14443a"] = card
            except PM3Error:
                pass

        if on_progress:
            ret = on_progress({"type": "hf_search", "phase": "15693"})
            if asyncio.iscoroutine(ret):
                await ret

        if self.iso15:
            try:
                tag = await self.iso15.scan()
                if tag.get("uid"):
                    results["iso15693"] = tag
            except PM3Error:
                pass

        results["found"] = len(results) > 0
        return results

    async def sniff(self, samples: int = 0, skip: int = 0,
                    on_progress: ProgressCallback = None) -> dict:
        """Sniff HF traffic."""
        payload = struct.pack("<II", samples, skip) if samples else b""
        resp = await self._t.send_ng(Cmd.HF_SNIFF, payload, timeout=30.0)
        return {"status": resp.status, "data": resp.data.hex()}

    async def dropfield(self) -> dict:
        """Turn off HF field."""
        resp = await self._t.send_ng(Cmd.HF_DROPFIELD)
        return {"status": resp.status}
