import json
from django.db import models
from django.utils import timezone


class KafkaLog(models.Model):
    # request data and response_data store as TextField, incase got return or send somethings in string so cant store in jsonField
    request_id = models.CharField(max_length=100, unique=True, null=True)
    request_topic = models.CharField(max_length=200, null=True)
    request_header = models.TextField(null=True, blank=True)
    request_data = models.TextField(null=True, blank=True)
    response_topic = models.CharField(max_length=200, null=True)
    response_header = models.TextField(null=True, blank=True)
    response_data = models.TextField(null=True, blank=True)
    request_at = models.DateTimeField(null=True)
    response_at = models.DateTimeField(null=True)
    extra_data = models.TextField(null=True, blank=True)
    socket_id = models.CharField(max_length=155, null=True, db_comment="remark to know need push to which socket")

    class Meta:
        db_table = "kafka_log"

    @staticmethod
    def insert_response(request_id, response_topic, response_data, socket_id: None, response_header=None):
        if isinstance(response_data, (dict, list)):
            response_data = json.dumps(response_data)
        else:
            response_data = str(response_data)
        if isinstance(response_header, (dict, list)):
            response_header = json.dumps(response_header)
        log = KafkaLog.objects.create(
            request_id=request_id,
            response_topic=response_topic,
            response_header=response_header,
            response_data=response_data,
            response_at=timezone.now(),
            socket_id=socket_id,
        )
        return log

    @staticmethod
    def insert_request(request_id, request_topic, request_data, socket_id: None, request_header=None):
        if isinstance(request_data, (dict, list)):
            request_data = json.dumps(request_data)
        else:
            request_data = str(request_data)
        if request_header is not None and not isinstance(request_header, str):
            # headers may be list of (key, bytes) tuples from confluent producer
            try:
                serializable = []
                for item in request_header:
                    if isinstance(item, (list, tuple)) and len(item) >= 2:
                        key, value = item[0], item[1]
                        if isinstance(value, bytes):
                            value = value.decode("utf-8", errors="replace")
                        serializable.append([key, value])
                    else:
                        serializable.append(item)
                request_header = json.dumps(serializable)
            except Exception:
                request_header = str(request_header)
        log = KafkaLog.objects.create(
            request_id=request_id,
            request_topic=request_topic,
            request_header=request_header,
            request_data=request_data,
            request_at=timezone.now(),
            socket_id=socket_id,
        )
        return log.id

    @staticmethod
    def update_response(response_topic, response_data, response_header=None):
        request_not_found = True
        try:
            request_id = response_data.get("request_id") if isinstance(response_data, dict) else None
            if isinstance(response_data, (dict, list)):
                response_data = json.dumps(response_data)
            else:
                response_data = str(response_data)

            if isinstance(response_header, (dict, list)):
                response_header = json.dumps(response_header)
            else:
                response_header = str(response_header) if response_header is not None else None
            if request_id:
                log = KafkaLog.objects.filter(request_id=request_id).first()
                if log:
                    log.response_data = response_data
                    log.response_header = response_header
                    log.response_topic = response_topic
                    log.response_at = timezone.now()
                    log.save()
                    request_not_found = False
                    return log

            if request_not_found:
                # even no request id or not found the request, also store the result, just for record purpose
                KafkaLog.objects.create(
                    response_data=response_data,
                    response_topic=response_topic,
                    response_header=response_header,
                    response_at=timezone.now(),
                )

        except KafkaLog.DoesNotExist:
            pass
