import json
import logging
import string
import threading
from typing import Iterable

from bs4 import BeautifulSoup
from django.contrib import messages
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.http.response import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

from base.models import Announcement
from employee.models import Employee
from horilla.horilla_middlewares import _thread_locals
from notifications.signals import notify
from whatsapp.flows import (
    get_asset_category_flow_json,
    get_attendance_request_json,
    get_bonus_point_json,
    get_leave_request_json,
    get_reimbursement_request_json,
    get_shift_request_json,
    get_work_type_request_json,
)
from whatsapp.models import WhatsappCredientials
from whatsapp.utils import (
    asset_request_create,
    attendance_request_create,
    bonus_point_create,
    create_flow,
    create_help_message,
    create_template_buttons,
    create_welcome_message,
    leave_request_create,
    publish_flow,
    reimbursement_create,
    send_document_message,
    send_flow_message,
    send_image_message,
    send_template_message,
    send_text_message,
    shift_create,
    update_flow,
    work_type_create,
)

DETAILED_FLOW = [
    {
        "template_name": "leave",
        "flow_name": "leave_request_flow",
        "flow_json": get_leave_request_json(),
    },
    {
        "template_name": "shift",
        "flow_name": "shift_request",
        "flow_json": get_shift_request_json(),
    },
    {
        "template_name": "bonus_point",
        "flow_name": "bonus_point_flow",
        "flow_json": get_bonus_point_json(),
    },
    {
        "template_name": "reimbursement",
        "flow_name": "reimbursement_flow",
        "flow_json": get_reimbursement_request_json(),
    },
    {
        "template_name": "work_type",
        "flow_name": "work_type_flow",
        "flow_json": get_work_type_request_json(),
    },
    {
        "template_name": "attendance",
        "flow_name": "attendance_flow",
        "flow_json": get_attendance_request_json(),
    },
    {
        "template_name": "asset",
        "flow_name": "asset_flow",
        "flow_json": get_asset_category_flow_json(),
    },
]

processed_messages = set()
logger = logging.getLogger(__name__)


def clean_string(s):
    """
    Cleans a given string by removing punctuation and converting it to lowercase.

    Args:
        s (str): The string to clean.

    Returns:
        str: The cleaned string, or the original string if an error occurs.
    """

    try:
        translator = str.maketrans("", "", string.punctuation + " _")
        cleaned_string = s.translate(translator).lower()
        return cleaned_string
    except:
        return s


@csrf_exempt
def whatsapp(request):
    """
    Handles incoming WhatsApp webhook requests.

    Args:
        request (HttpRequest): The incoming HTTP request.

    Returns:
        HttpResponse: A response indicating the status of the operation.
    """

    if request.method == "GET":
        credentials = WhatsappCredientials.objects.first()

        token = request.GET.get("hub.verify_token")
        challenge = request.GET.get("hub.challenge")
        if token == credentials.meta_webhook_token:
            return HttpResponse(challenge, status=200)

    if request.method == "POST":
        data = json.loads(request.body)
        if "object" in data and "entry" in data:
            if data["object"] == "whatsapp_business_account":
                for entry in data["entry"]:
                    changes = entry.get("changes", [])[0]
                    value = changes.get("value", {})

                    if "messages" in value:
                        try:
                            metadata = value.get("metadata", {})
                            contacts = value.get("contacts", [])[0]
                            messages = value.get("messages", [])[0]

                            message_id = messages.get("id")
                            if message_id in processed_messages:
                                continue

                            processed_messages.add(message_id)

                            profile_name = contacts.get("profile", {}).get("name")
                            from_number = messages.get("from")
                            text = messages.get("text", {}).get("body")
                            type = messages.get("type", {})
                            flow_response = (
                                messages.get("interactive", {})
                                .get("nfm_reply", {})
                                .get("response_json", {})
                            )

                            if type == "interactive":
                                flow_conversion(from_number, flow_response)
                            if type == "button":
                                text = messages.get("button", {}).get("text", {})

                            text = clean_string(text)

                            # Handle different messages based on cleaned text
                            if text == "helloworld":
                                send_template_message(from_number, "hello_world")
                            elif text == "help":
                                send_template_message(from_number, "help_50")
                            elif text in ["asset", "assetrequest"]:
                                send_flow_message(from_number, "asset")
                            elif text in ["shift", "shiftrequest"]:
                                send_flow_message(from_number, "shift")
                            elif text in ["worktype", "worktyperequest"]:
                                send_flow_message(from_number, "work_type")
                            elif text in ["attendance", "attendancerequest"]:
                                send_flow_message(from_number, "attendance")
                            elif text in ["leave", "leaverequest"]:
                                send_flow_message(from_number, "leave")
                            elif text in ["reimbursement", "reimbursementrequest"]:
                                send_flow_message(from_number, "reimbursement")
                            elif text in ["bonus", "bonuspoint", "bonuspointredeem"]:
                                send_flow_message(from_number, "bonus_point")
                            elif text in [
                                "hi",
                                "hello",
                                "goodmorning",
                                "goodafternoon",
                                "goodevening",
                                "goodnight",
                                "hlo",
                            ]:
                                send_template_message(from_number, "welcome_message_50")
                            elif text == "image":
                                try:
                                    image_relative_url = (
                                        Employee.objects.filter(phone=from_number)
                                        .first()
                                        .employee_profile.url
                                    )
                                    image_link = request.build_absolute_uri(
                                        image_relative_url
                                    )
                                except Exception as e:
                                    print(e)

                                send_image_message(from_number, image_link)
                            elif text == "document":
                                try:
                                    document_relative_url = (
                                        Employee.objects.filter(phone=from_number)
                                        .first()
                                        .employee_profile.url
                                    )
                                    document_link = request.build_absolute_uri(
                                        document_relative_url
                                    )
                                except Exception as e:
                                    print(e)

                                send_document_message(from_number, document_link)
                            elif text == "string":
                                send_text_message(
                                    from_number, "test message", "test heading"
                                )
                            else:
                                if text:
                                    send_template_message(
                                        from_number, "button_template_50"
                                    )

                        except KeyError as e:
                            print(f"KeyError: {e}")
                            return HttpResponse("Bad Request", status=400)
                        except Exception as e:
                            print(f"Unexpected error: {e}")
                            return HttpResponse("Internal Server Error", status=500)

                        return HttpResponse("Message processed", status=403)

    return HttpResponse("error", status=200)


def create_generic_templates(request, id):
    """
    Creates generic message templates for WhatsApp.

    Args:
        request (HttpRequest): The incoming HTTP request.

    Returns:
        HttpResponse: A response indicating the success or failure of template creation.
    """

    try:
        create_template_buttons(id)
        create_welcome_message(id)
        create_help_message(id)
        create_flows(id)

        credential = WhatsappCredientials.objects.get(id=id)
        credential.created_templates = True
        credential.save()

        messages.success(request, "Message templates and flows created successfully.")
    except:
        messages.error(request, "Message templates and flows creation failed.")
    return HttpResponse("<script>window.location.reload();</script>")


@csrf_exempt
def create_flows(cred_id):
    """
    Creates and publishes flows based on predefined details.

    Args:
        request (HttpRequest): The incoming HTTP request.

    Returns:
        HttpResponse: A response indicating the success or failure of flow creation.
    """

    try:
        for flow in DETAILED_FLOW:
            template_name = flow["template_name"]
            flow_name = flow["flow_name"]
            flow_json = flow["flow_json"]
            credential = WhatsappCredientials.objects.get(id=cred_id)

            # Create flow
            create_response = create_flow(flow_name, template_name, cred_id)
            create_response_data = create_response.json()

            flow_id = create_response_data.get("id")
            if not flow_id:
                return HttpResponse(
                    json.dumps(create_response_data),
                    status=create_response.status_code,
                    content_type="application/json",
                )

            # Update flow
            update_response = update_flow(flow_id, flow_json, credential.meta_token)
            update_response_data = update_response.json()
            if update_response_data.get("validation_error", {}):
                return HttpResponse(
                    json.dumps(update_response_data),
                    status=update_response.status_code,
                    content_type="application/json",
                )

            # Publish flow
            publish_response = publish_flow(flow_id, credential.meta_token)
            publish_response_data = publish_response.json()
            if publish_response_data.get("error", {}):
                return HttpResponse(
                    json.dumps(publish_response_data),
                    status=publish_response.status_code,
                    content_type="application/json",
                )

        return HttpResponse(
            json.dumps({"message": "Flow created successfully"}),
            status=200,
            content_type="application/json",
        )

    except Exception as e:
        print(f"Unexpected error: {e}")
        return HttpResponse(
            json.dumps({"error": str(e)}), status=500, content_type="application/json"
        )


def send_notification_task(recipient, verb, redirect, icon):
    """
    Background task to send a notification message via WhatsApp.
    """
    try:
        request = getattr(_thread_locals, "request", None)
        link = request.build_absolute_uri(redirect) if redirect else None
        message = f"{verb}\nFor more details, \n{link}." if link else verb

        recipients = (
            recipient
            if isinstance(recipient, Iterable) and not isinstance(recipient, str)
            else [recipient]
        )

        for user in recipients:
            phone_number = user.employee_get.phone
            if phone_number:
                send_text_message(phone_number, message)
            else:
                print(f"No phone number available for recipient {user}")

    except Exception as e:
        print(f"Error in notification task: {e}")


# @receiver(notify)
def send_notification_on_whatsapp(sender, recipient, verb, redirect, icon, **kwargs):

    thread = threading.Thread(
        target=send_notification_task, args=(recipient, verb, redirect, icon)
    )
    thread.start()


def send_announcement_task(instance, request):
    """
    Background task to send an announcement message via WhatsApp.
    """
    employees = instance.employees.all()
    header = instance.title
    body = instance.description

    soup = BeautifulSoup(body, "html.parser")
    paragraphs = []
    for element in soup.find_all(["p", "ul", "ol", "h1", "h2", "h3", "h4", "h5", "h6"]):
        if element.name in ["h1", "h2", "h3", "h4", "h5", "h6"]:
            heading_text = element.get_text(strip=True).capitalize()
            paragraphs.append(f"*{heading_text}*")

        elif element.name in ["ul", "ol"]:
            list_items = []
            for li in element.find_all("li"):
                item_text = []
                for child in li.children:
                    if child.name == "code":
                        item_text.append(f"`{child.get_text()}`")
                    elif child.name in ["strong", "b"]:
                        item_text.append(f"*{child.get_text()}*")
                    elif child.name == "span":
                        item_text.append(child.get_text())
                    elif child.name == "a":
                        item_text.append(child.get_text())
                    elif isinstance(child, str):
                        item_text.append(child.strip())
                list_items.append("• " + " ".join(item_text).strip())
            paragraphs.append("\n".join(list_items))

        elif element.name == "p":
            para_text = []
            for child in element.children:
                if child.name == "code":
                    para_text.append(f"`{child.get_text()}`")
                elif child.name in ["strong", "b"]:
                    para_text.append(f"*{child.get_text()}*")
                elif child.name == "span":
                    para_text.append(child.get_text())
                elif child.name == "a":
                    para_text.append(child.get_text())
                elif isinstance(child, str):
                    para_text.append(child.strip())
            paragraphs.append(" ".join(para_text).strip())
    final_text = "\n\n".join(paragraphs)

    for employee in employees:
        number = employee.phone
        send_text_message(number, final_text, header)
        for attachment in instance.attachments.all():
            link = attachment.file.url
            document_link = request.build_absolute_uri(link)
            send_document_message(number, document_link)


# @receiver(post_save, sender=Announcement)
def send_announcement_on_whatsapp(sender, instance, created, **kwargs):
    if not created:
        request = getattr(_thread_locals, "request", None)

        thread = threading.Thread(
            target=send_announcement_task, args=(instance, request)
        )
        thread.start()


def flow_conversion(number, flow_response_json):
    """
    Processes a flow response based on the type of request.

    Args:
        number (str): The phone number of the employee.
        flow_response_json (str): The JSON response from the flow.

    Returns:
        Response: The response from sending a message.
    """

    employee = Employee.objects.filter(phone=number).first()
    flow_response = json.loads(flow_response_json)
    message = "Something went wrong ......"
    type = flow_response["type"]

    if type == "shift_request":
        message = shift_create(employee, flow_response)
    elif type == "leave_request":
        message = leave_request_create(employee, flow_response)
    elif type == "work_type":
        message = work_type_create(employee, flow_response)
    elif type == "asset_request":
        message = asset_request_create(employee, flow_response)
    elif type == "attendance_request":
        message = attendance_request_create(employee, flow_response)
    elif type == "bonus_point":
        message = bonus_point_create(employee, flow_response)
    elif type == "reimbursement":
        message = reimbursement_create(employee, flow_response)

    response = send_text_message(number, message)
    return response


def whatsapp_credential_view(request):
    """
    Renders the WhatsApp credentials view.

    Args:
        request (HttpRequest): The incoming HTTP request.

    Returns:
        HttpResponse: The rendered credentials view.
    """

    return render(request, "whatsapp/credentials_view.html", {})
