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

import pytest
from rest_framework import status
from rest_framework.test import APIClient

from plane.db.models import Intake, IntakeIssue, Issue, Project, ProjectMember, State, WorkspaceMember
from plane.db.models.intake import IntakeIssueStatus
from plane.db.models.project import ROLE
from plane.db.models.state import StateGroup


@pytest.mark.contract
class TestExternalContoursBoardAPI:
    def get_board_url(self, workspace_slug: str, project_id) -> str:
        return f"/api/workspaces/{workspace_slug}/projects/{project_id}/external-contours/board/"

    def get_board_item_url(self, workspace_slug: str, project_id, request_id) -> str:
        return f"/api/workspaces/{workspace_slug}/projects/{project_id}/external-contours/board-items/{request_id}/"

    def create_project_with_member(self, workspace, user, name: str, identifier: str, intake_view: bool = False) -> Project:
        project = Project.objects.create(
            name=name,
            identifier=identifier,
            workspace=workspace,
            intake_view=intake_view,
        )
        ProjectMember.objects.create(project=project, member=user, role=ROLE.ADMIN.value, is_active=True)
        return project

    def create_state(self, project: Project, name: str, group: str, color: str, default: bool = False) -> State:
        return State.objects.create(
            project=project,
            workspace=project.workspace,
            name=name,
            group=group,
            color=color,
            sequence=1000,
            default=default,
        )

    def create_external_contour_request(self, source_project: Project, target_project: Project, requested_by, state: State):
        intake = Intake.objects.create(
            name="External Contours Bridge",
            project=target_project,
            is_default=False,
        )
        issue = Issue.objects.create(
            project=target_project,
            state=state,
            name="Cross-project request",
            description_html="<p>Need help</p>",
            priority="high",
            created_by=requested_by,
        )
        return IntakeIssue.objects.create(
            intake=intake,
            project=target_project,
            issue=issue,
            status=IntakeIssueStatus.ACCEPTED.value,
            extra={
                "bridge": "external-contours",
                "source_project_id": str(source_project.id),
                "source_project_name": source_project.name,
                "target_project_id": str(target_project.id),
                "target_project_name": target_project.name,
                "requested_by_id": str(requested_by.id),
                "requested_by_name": requested_by.display_name,
                "requested_at": issue.created_at.isoformat() if issue.created_at else None,
            },
        )

    @pytest.mark.django_db
    def test_source_project_member_gets_outgoing_board_items(self, workspace, create_user):
        source_user = create_user
        target_user = type(source_user).objects.create_user(email="target-board@example.com", username="target-board")
        WorkspaceMember.objects.create(workspace=workspace, member=target_user, role=ROLE.ADMIN.value, is_active=True)

        source_project = self.create_project_with_member(workspace, source_user, "Source Board", "SRCBRD")
        target_project = self.create_project_with_member(workspace, target_user, "Target Board", "TGTBRD", intake_view=True)
        open_state = self.create_state(target_project, "Todo", StateGroup.UNSTARTED.value, "#cccccc", default=True)
        contour_request = self.create_external_contour_request(source_project, target_project, source_user, open_state)

        client = APIClient()
        client.force_authenticate(user=source_user)
        response = client.get(self.get_board_url(workspace.slug, source_project.id), format="json")

        assert response.status_code == status.HTTP_200_OK
        columns = {column["key"]: column for column in response.data["columns"]}

        assert columns["outgoing"]["total_count"] == 1
        assert columns["incoming"]["total_count"] == 0
        assert columns["outgoing"]["results"][0]["id"] == str(contour_request.id)
        assert columns["outgoing"]["results"][0]["direction"] == "outgoing"
        assert columns["outgoing"]["results"][0]["capabilities"]["can_open_target_issue"] is False

    @pytest.mark.django_db
    def test_target_project_member_gets_incoming_board_items(self, workspace, create_user):
        source_user = create_user
        target_user = type(source_user).objects.create_user(email="incoming-board@example.com", username="incoming-board")
        WorkspaceMember.objects.create(workspace=workspace, member=target_user, role=ROLE.ADMIN.value, is_active=True)

        source_project = self.create_project_with_member(workspace, source_user, "Source Incoming", "SRCINC")
        target_project = self.create_project_with_member(workspace, target_user, "Target Incoming", "TGTINC", intake_view=True)
        open_state = self.create_state(target_project, "Todo", StateGroup.UNSTARTED.value, "#cccccc", default=True)
        contour_request = self.create_external_contour_request(source_project, target_project, source_user, open_state)

        client = APIClient()
        client.force_authenticate(user=target_user)
        response = client.get(self.get_board_url(workspace.slug, target_project.id), format="json")

        assert response.status_code == status.HTTP_200_OK
        columns = {column["key"]: column for column in response.data["columns"]}

        assert columns["outgoing"]["total_count"] == 0
        assert columns["incoming"]["total_count"] == 1
        assert columns["incoming"]["results"][0]["id"] == str(contour_request.id)
        assert columns["incoming"]["results"][0]["direction"] == "incoming"
        assert columns["incoming"]["results"][0]["capabilities"]["can_open_target_issue"] is True

    @pytest.mark.django_db
    def test_board_item_detail_resolves_perspective_and_capabilities(self, workspace, create_user):
        source_user = create_user
        target_user = type(source_user).objects.create_user(email="detail-board@example.com", username="detail-board")
        WorkspaceMember.objects.create(workspace=workspace, member=target_user, role=ROLE.ADMIN.value, is_active=True)

        source_project = self.create_project_with_member(workspace, source_user, "Source Detail", "SRCDET")
        target_project = self.create_project_with_member(workspace, target_user, "Target Detail", "TGTDET", intake_view=True)
        closed_state = self.create_state(target_project, "Done", StateGroup.COMPLETED.value, "#00ff00", default=True)
        contour_request = self.create_external_contour_request(source_project, target_project, source_user, closed_state)

        source_client = APIClient()
        source_client.force_authenticate(user=source_user)
        source_response = source_client.get(
            self.get_board_item_url(workspace.slug, source_project.id, contour_request.id),
            format="json",
        )

        assert source_response.status_code == status.HTTP_200_OK
        assert source_response.data["direction"] == "outgoing"
        assert source_response.data["capabilities"]["can_source_decide"] is True
        assert source_response.data["capabilities"]["can_open_target_issue"] is False

        target_client = APIClient()
        target_client.force_authenticate(user=target_user)
        target_response = target_client.get(
            self.get_board_item_url(workspace.slug, target_project.id, contour_request.id),
            format="json",
        )

        assert target_response.status_code == status.HTTP_200_OK
        assert target_response.data["direction"] == "incoming"
        assert target_response.data["capabilities"]["can_source_decide"] is False
        assert target_response.data["capabilities"]["can_open_target_issue"] is True
