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

from celery import shared_task
from django.db import transaction
from django.utils import timezone
from typing import Optional, Dict
import json

from plane.db.models import Issue, IssueDescriptionVersion
from plane.utils.exception_logger import log_exception


def should_update_existing_version(
    version: IssueDescriptionVersion, user_id: str, max_time_difference: int = 600
) -> bool:
    if not version:
        return

    time_difference = (timezone.now() - version.last_saved_at).total_seconds()
    return str(version.owned_by_id) == str(user_id) and time_difference <= max_time_difference


def update_existing_version(version: IssueDescriptionVersion, issue) -> None:
    version.description_json = issue.description_json
    version.description_html = issue.description_html
    version.description_binary = issue.description_binary
    version.description_stripped = issue.description_stripped
    version.last_saved_at = timezone.now()

    version.save(
        update_fields=[
            "description_json",
            "description_html",
            "description_binary",
            "description_stripped",
            "last_saved_at",
        ]
    )


@shared_task
def issue_description_version_task(updated_issue, issue_id, user_id, is_creating=False) -> Optional[bool]:
    try:
        # Parse updated issue data
        current_issue: Dict = json.loads(updated_issue) if updated_issue else {}

        # Get current issue
        issue = Issue.objects.get(id=issue_id)

        # Check if description has changed
        if current_issue.get("description_html") == issue.description_html and not is_creating:
            return

        with transaction.atomic():
            # Get latest version
            latest_version = (
                IssueDescriptionVersion.objects.filter(issue_id=issue_id).order_by("-last_saved_at").first()
            )

            # Determine whether to update existing or create new version
            if should_update_existing_version(version=latest_version, user_id=user_id):
                update_existing_version(latest_version, issue)
            else:
                IssueDescriptionVersion.log_issue_description_version(issue, user_id)

            return

    except Issue.DoesNotExist:
        # Issue no longer exists, skip processing
        return
    except json.JSONDecodeError as e:
        log_exception(f"Invalid JSON for updated_issue: {e}")
        return
    except Exception as e:
        log_exception(f"Error processing issue description version: {e}")
        return
