# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.

import json

from django.core.serializers.json import DjangoJSONEncoder
from django.utils import timezone
from django.utils.html import escape

from plane.app.serializers import IssueCommentSerializer
from plane.db.models import IssueComment, Notification, Project


EXTERNAL_CONTOUR_NOTIFICATION_FIELDS = {"state", "comment", "attachment", "description"}


def build_external_contour_comment_html(comment: str) -> str:
    escaped_comment = escape((comment or "").strip())
    escaped_comment = escaped_comment.replace("\n", "<br />")
    return f"<p>{escaped_comment}</p>"


def create_external_contour_issue_comment(*, issue, actor, comment: str, origin: str):
    from plane.bgtasks.issue_activities_task import issue_activity

    comment_html = build_external_contour_comment_html(comment)
    serializer = IssueCommentSerializer(data={"comment_html": comment_html})
    serializer.is_valid(raise_exception=True)
    serializer.save(project_id=issue.project_id, issue_id=issue.id, actor=actor)
    issue_activity.delay(
        type="comment.activity.created",
        requested_data=json.dumps(serializer.data, cls=DjangoJSONEncoder),
        actor_id=str(actor.id),
        issue_id=str(issue.id),
        project_id=str(issue.project_id),
        current_instance=None,
        epoch=int(timezone.now().timestamp()),
        notification=True,
        origin=origin,
    )
    return serializer.data


def create_external_contour_notification(*, contour_request, issue, issue_activity_data):
    extra = contour_request.extra or {}
    receiver_id = extra.get("requested_by_id")
    source_project_id = extra.get("source_project_id")
    field = issue_activity_data.get("field")
    actor_id = issue_activity_data.get("actor_id") or (issue_activity_data.get("actor_detail") or {}).get("id")

    if not receiver_id or not source_project_id or not field:
        return None

    if field not in EXTERNAL_CONTOUR_NOTIFICATION_FIELDS:
        return None

    if str(receiver_id) == str(actor_id):
        return None

    source_project = Project.objects.filter(
        pk=source_project_id,
        workspace_id=issue.workspace_id,
        archived_at__isnull=True,
    ).first()

    if not source_project:
        return None

    issue_comment = (
        IssueComment.objects.filter(
            id=issue_activity_data.get("issue_comment"),
            issue_id=issue.id,
            project_id=issue.project_id,
            workspace_id=issue.workspace_id,
        ).first()
        if issue_activity_data.get("issue_comment")
        else None
    )

    return Notification(
        workspace=source_project.workspace,
        project=source_project,
        sender=f"in_app:external_contours:{field}",
        triggered_by_id=actor_id,
        receiver_id=receiver_id,
        entity_identifier=issue.id,
        entity_name="issue",
        title=issue_activity_data.get("comment") or "External contour updated",
        data={
            "issue": {
                "id": str(contour_request.id),
                "name": str(issue.name),
                "identifier": str(issue.project.identifier),
                "sequence_id": issue.sequence_id,
                "state_name": issue.state.name if issue.state else None,
                "state_group": issue.state.group if issue.state else None,
                "project_id": str(source_project.id),
                "workspace_slug": str(source_project.workspace.slug),
                "external_contour_request_id": str(contour_request.id),
                "target_issue_id": str(issue.id),
                "target_project_id": str(issue.project_id),
                "target_project_name": str(issue.project.name),
                "source_project_id": str(source_project.id),
                "source_project_name": str(source_project.name),
            },
            "issue_activity": {
                "id": str(issue_activity_data.get("id")),
                "verb": str(issue_activity_data.get("verb")),
                "field": str(field),
                "actor": str(actor_id),
                "new_value": str(issue_activity_data.get("new_value")),
                "old_value": str(issue_activity_data.get("old_value")),
                "issue_comment": str(issue_comment.comment_stripped if issue_comment is not None else ""),
                "old_identifier": (
                    str(issue_activity_data.get("old_identifier")) if issue_activity_data.get("old_identifier") else None
                ),
                "new_identifier": (
                    str(issue_activity_data.get("new_identifier")) if issue_activity_data.get("new_identifier") else None
                ),
            },
        },
    )
