import argparse
import asyncio
import sys
import logging
import binascii

from .ioclient import TcpNmea2000Gateway
from .decoder import NMEA2000Decoder
from .encoder import NMEA2000Encoder
from .pgns import *

logger = logging.getLogger(__name__)

async def tcp_client(ip, port):
    print(f"Connecting to {ip}:{port}")
    client = TcpNmea2000Gateway(ip, port)
    client.set_receive_callback(handle_received_data)  # Register callback
    await client.connect()

    while True:
        line = await asyncio.to_thread(sys.stdin.readline)
        if not line:
            break
        line = line.strip()
        if line:
            try:
                message = NMEA2000Message.from_json(line)
            except Exception:
                print ("Not valid NMEA2000Message json")
                continue
            await client.send(message)
    await client.close()

async def handle_received_data(message: NMEA2000Message):
    """User-defined callback function for received data."""
    print(f"Callback: Received {message}")


def parse(filename: str, decoder: NMEA2000Decoder):
    data_length = 8
    try:
        with open(filename, 'r') as file:
            while True:
                line = file.readline()
                if not line:
                    break
                if line.startswith('#') or len(line) <= 1:
                    continue
                line = line.strip()
                parts = line.split(',')
                date = parts[0]
                priority = int(parts[1])
                pgn = int(parts[2])
                src = int(parts[3])
                dest = int(parts[4])
                no_idea = parts[5]
                can_data = parts[6:6 + data_length][::-1]
                can_data_bytes = [int(byte, 16) for byte in can_data]
                can_data_hex = binascii.hexlify(bytes(can_data_bytes)).decode('ascii')
                logger.info(f'Processing: {can_data_hex}')
                decoder.decode(date, priority, pgn, src, dest, can_data_hex)
    except KeyboardInterrupt:
        sys.stdout.flush()
        pass

def main():
    logging.basicConfig(filename='parser.log', level=logging.NOTSET)
    parser = argparse.ArgumentParser(description="NMEA 2000 CLI Tool")
    parser.add_argument("--verbose", action="store_true", help="Enable verbose mode")
    subparsers = parser.add_subparsers(dest="command", required=True)

    # Decode command
    decode_parser = subparsers.add_parser("decode", help="Decode an NMEA 2000 frame")
    
    # Either provide a frame string or a file
    decode_parser.add_argument(
        "--frame", 
        type=str, 
        help="Hex-encoded NMEA 2000 frame (optional if file is provided)"
    )
    decode_parser.add_argument(
        "--file", 
        type=str, 
        help="Path to a file containing a Hex-encoded NMEA 2000 frame"
    )

    # Encode command
    encode_parser = subparsers.add_parser("encode", help="Encode an NMEA 2000 frame")
    
    # Either provide a frame string or a file
    encode_parser.add_argument(
        "--frame", 
        type=str, 
        help="json NMEA 2000 frame (optional if file is provided)"
    )
    encode_parser.add_argument(
        "--file", 
        type=str, 
        help="Path to a file containing a JSON NMEA 2000 frame"
    )

    # TCP client command
    tcp_client_parser = subparsers.add_parser("tcp_client", help="start TCP client to CANBUS gateway (for example, ECAN-E01 or ECAN-W01)")
    tcp_client_parser.add_argument(
        "--server", 
        type=str, 
        help="Server IP address"
    )
    tcp_client_parser.add_argument(
        "--port", 
        type=int, 
        help="Server port number"
    )


    # Parse arguments
    args = parser.parse_args()

    if args.verbose:
        root_logger = logging.getLogger()
        root_logger.setLevel(logging.DEBUG)  # Set the global log level
        root_logger.addHandler(logging.StreamHandler())

    if args.command == "decode":
        decoder = NMEA2000Decoder()

        # Decode from a frame string if provided
        if args.frame:
            decoded = decoder.decode_actisense_string(args.frame)
            print(decoded.to_json())

        # Decode from a file if provided
        elif args.file:
            parse(args.file, decoder)
        else:
            print("Error: You must provide either a frame or a file to decode.")
            exit(1)

    elif args.command == "encode":
        encoder = NMEA2000Encoder()

        # Encode from a frame json
        if args.frame:
            frame_str = args.frame
            print(f"Encoding frame: {frame_str}")
            encoded = encoder.encode_actisense(NMEA2000Message.from_json(args.frame))
            print(encoded)

        # Encode from a json file
        if args.file:
            with open(args.file, 'r') as file:
                json_string = file.read()
            frame_str = args.frame
            encoded = encoder.encode_actisense(NMEA2000Message.from_json(json_string))
            print(encoded)
            
    elif args.command == "tcp_client":
        asyncio.run(tcp_client(args.server, args.port))

if __name__ == "__main__":
    main()