import os
import uuid
import pytest
import asyncio

import polarion_rest_client as prc
from polarion_rest_client.client import PolarionClient, PolarionAsyncClient
from polarion_rest_client.document_comment import DocumentComment


# --- Synchronous Implementation ---
def _run_comment_test_sync(api, project_id, space_id, document_name, allow_create):
    """Run Document Comment tests in sync mode."""
    # -------- LIST (always available) ----------
    print(f"Listing comments for {project_id}/{space_id}/{document_name}")
    comments = api.list(project_id, space_id, document_name, page_size=10)
    print(f"  Found {len(comments)} comments")

    if not allow_create:
        # GET-only mode: just list and optionally get first comment
        if comments:
            first_id = comments[0].get("id", "").split("/")[-1]
            if first_id:
                got = api.get(project_id, space_id, document_name, first_id)
                assert (got.get("data") or {}).get("id", "").endswith(f"/{first_id}")
        return

    # -------- CREATE + GET + UPDATE ---
    token = uuid.uuid4().hex[:6]
    text = f"Test comment created by sync tests ({token})"

    print(f"Creating comment ({token})")
    created = api.create(
        project_id,
        space_id,
        document_name,
        text=text,
        text_type="text/plain",
    )
    created_id = created.get("id", "")
    print(f"  Created: {created_id}")
    assert created_id

    # Extract comment ID from full ID
    comment_id = created_id.split("/")[-1] if "/" in created_id else created_id

    # GET the created comment
    print(f"Fetching comment: {comment_id}")
    got = api.get(project_id, space_id, document_name, comment_id, fields_comments=["@all"])
    got_id = (got.get("data") or {}).get("id", "")
    assert got_id.endswith(f"/{comment_id}") or comment_id in got_id

    # Note: The Polarion API only supports updating the 'resolved' attribute for comments.
    # Text and title cannot be modified after creation.

    # Test RESOLVE
    print("Resolving comment...")
    api.resolve(project_id, space_id, document_name, comment_id)

    got3 = api.get(project_id, space_id, document_name, comment_id, fields_comments=["@all"])
    attrs3 = ((got3.get("data") or {}).get("attributes") or {})
    # Note: resolved attribute might not be returned depending on API version
    print(f"  Resolved status: {attrs3.get('resolved', 'not returned')}")

    # Test UNRESOLVE
    print("Unresolving comment...")
    api.unresolve(project_id, space_id, document_name, comment_id)

    # Test REPLY
    print("Creating reply to comment...")
    reply = api.reply(
        project_id,
        space_id,
        document_name,
        comment_id,
        text=f"Reply to comment ({token})",
    )
    reply_id = reply.get("id", "")
    print(f"  Reply created: {reply_id}")
    assert reply_id


# --- Asynchronous Implementation ---
async def _run_comment_test_async(api, project_id, space_id, document_name, allow_create):
    """Run Document Comment tests in async mode."""
    # -------- LIST (always available) ----------
    print(f"Listing comments for {project_id}/{space_id}/{document_name}")
    comments = await api.list(project_id, space_id, document_name, page_size=10)
    print(f"  Found {len(comments)} comments")

    if not allow_create:
        # GET-only mode
        if comments:
            first_id = comments[0].get("id", "").split("/")[-1]
            if first_id:
                got = await api.get(project_id, space_id, document_name, first_id)
                assert (got.get("data") or {}).get("id", "").endswith(f"/{first_id}")
        return

    # -------- CREATE + GET + UPDATE ---
    token = uuid.uuid4().hex[:6]
    text = f"Test comment created by async tests ({token})"

    print(f"Creating comment ({token})")
    created = await api.create(
        project_id,
        space_id,
        document_name,
        text=text,
        text_type="text/plain",
    )
    created_id = created.get("id", "")
    print(f"  Created: {created_id}")
    assert created_id

    comment_id = created_id.split("/")[-1] if "/" in created_id else created_id

    # GET
    print(f"Fetching comment: {comment_id}")
    got = await api.get(project_id, space_id, document_name, comment_id, fields_comments=["@all"])
    got_id = (got.get("data") or {}).get("id", "")
    assert got_id.endswith(f"/{comment_id}") or comment_id in got_id

    # Note: The Polarion API only supports updating the 'resolved' attribute for comments.
    # Text and title cannot be modified after creation.

    # Test RESOLVE
    print("Resolving comment...")
    await api.resolve(project_id, space_id, document_name, comment_id)

    # Test UNRESOLVE
    print("Unresolving comment...")
    await api.unresolve(project_id, space_id, document_name, comment_id)

    # Test REPLY
    print("Creating reply to comment...")
    reply = await api.reply(
        project_id,
        space_id,
        document_name,
        comment_id,
        text=f"Reply to comment ({token})",
    )
    reply_id = reply.get("id", "")
    print(f"  Reply created: {reply_id}")
    assert reply_id


# --- Test Entry Point ---
@pytest.mark.integration
@pytest.mark.parametrize("mode", ["sync", "async"])
def test_document_comment_crud_or_list_only(mode):
    """
    Runs Document Comment CRUD or LIST-only test in either sync or async mode.
    """
    project_id = os.getenv("POLARION_TEST_PROJECT_ID")
    space_id = os.getenv("POLARION_TEST_SPACE_ID") or "_default"
    document_name = os.getenv("POLARION_TEST_DOCUMENT_NAME")

    if not project_id:
        pytest.skip("Set POLARION_TEST_PROJECT_ID to run Document Comment tests.")
    if not document_name:
        pytest.skip("Set POLARION_TEST_DOCUMENT_NAME to run Document Comment tests.")

    allow_create = os.getenv("POLARION_TEST_DOC_CREATE_OK") == "1"

    if mode == "sync":
        try:
            pc = PolarionClient(**prc.get_env_vars())
        except Exception:
            pytest.skip("Polarion env vars not configured")
            return

        api = DocumentComment(pc)
        _run_comment_test_sync(api, project_id, space_id, document_name, allow_create)

    else:
        # Async Mode
        async def _async_wrapper():
            try:
                pc_async = PolarionAsyncClient(**prc.get_env_vars())
            except Exception:
                pytest.skip("Polarion env vars not configured")
                return
            except RuntimeError as e:
                if "AuthenticatedAsyncClient" in str(e) or "not available" in str(e):
                    pytest.skip(f"Async support missing in generated client: {e}")
                raise e

            async with pc_async as client:
                api = DocumentComment(client)
                await _run_comment_test_async(api, project_id, space_id, document_name, allow_create)

        asyncio.run(_async_wrapper())


@pytest.mark.integration
def test_document_comment_iter(polarion_test_client):
    """Test iterating over document comments."""
    project_id = os.getenv("POLARION_TEST_PROJECT_ID")
    space_id = os.getenv("POLARION_TEST_SPACE_ID") or "_default"
    document_name = os.getenv("POLARION_TEST_DOCUMENT_NAME")

    if not project_id or not document_name:
        pytest.skip("Set POLARION_TEST_PROJECT_ID and POLARION_TEST_DOCUMENT_NAME")

    api = DocumentComment(polarion_test_client)

    count = 0
    for comment in api.iter(project_id, space_id, document_name, page_size=10):
        assert "id" in comment or "type" in comment
        count += 1
        if count >= 5:  # Limit iteration for test
            break

    print(f"Iterated over {count} comments")
