import sys
from notion_client import Client
from tasks.utils import notion_utils

# Expected code blocks (language=go)
EXPECTED_CODE_BLOCKS = [
    {
        "caption": "Basic Go program",
        "code": (
            'package main\n\nimport "fmt"\n\nfunc main() {\n    fmt.Println("Hello, World!")\n}'
        ),
    },
    {
        "caption": "For loop in Go",
        "code": ("for i := 0; i < 5; i++ {\n    fmt.Println(i)\n}"),
    },
    {
        "caption": "Function definition in Go",
        "code": ("func add(a, b int) int {\n    return a + b\n}"),
    },
]

HEADER_TEXT = "Go"


def _normalize(text: str) -> str:
    """Remove trailing spaces on each line and strip leading/trailing blank lines."""
    return "\n".join(line.rstrip() for line in text.strip().splitlines())


def _find_page(notion: Client, main_id: str | None) -> str | None:
    """Return a page_id to verify against or None if not found."""
    page_id = None
    if main_id:
        found_id, object_type = notion_utils.find_page_or_database_by_id(
            notion, main_id
        )
        if found_id and object_type == "page":
            page_id = found_id
    if not page_id:
        page_id = notion_utils.find_page(notion, "Computer Science Student Dashboard")
    return page_id


def _has_bold_header_text(block, text: str) -> bool:
    """Generic bold header/paragraph check for a given text."""
    block_type = block.get("type")
    if block_type not in {"paragraph", "heading_1", "heading_2", "heading_3"}:
        return False
    rich_text_list = block.get(block_type, {}).get("rich_text", [])
    if not rich_text_list:
        return False
    plain = "".join(rt.get("plain_text", "") for rt in rich_text_list).strip()
    if plain != text:
        return False
    return any(rt.get("annotations", {}).get("bold", False) for rt in rich_text_list)


def _go_column_order_correct(notion: Client, page_id: str) -> bool:
    """Return True if there exists a column list where Python → Go → JavaScript order holds."""
    # Gather all blocks once (flat list) to locate column_list blocks
    all_blocks = notion_utils.get_all_blocks_recursively(notion, page_id)
    column_list_ids = [
        blk["id"] for blk in all_blocks if blk.get("type") == "column_list"
    ]

    for cl_id in column_list_ids:
        # Retrieve columns in explicit order
        columns = notion.blocks.children.list(block_id=cl_id).get("results", [])
        header_to_idx: dict[str, int] = {}
        for idx, col in enumerate(columns):
            # Recursively inspect blocks within this column
            col_blocks = notion_utils.get_all_blocks_recursively(notion, col["id"])
            for blk in col_blocks:
                if _has_bold_header_text(blk, "Python"):
                    header_to_idx.setdefault("Python", idx)
                elif _has_bold_header_text(blk, "Go"):
                    header_to_idx.setdefault("Go", idx)
                elif _has_bold_header_text(blk, "JavaScript"):
                    header_to_idx.setdefault("JavaScript", idx)
            # Short-circuit if all three found within current traversal
            if len(header_to_idx) == 3:
                break

        if (
            "Python" in header_to_idx
            and "Go" in header_to_idx
            and "JavaScript" in header_to_idx
            and header_to_idx["Python"]
            < header_to_idx["Go"]
            < header_to_idx["JavaScript"]
        ):
            return True
    return False


def _collect_code_blocks(blocks):
    """Return list of (code_content, caption) tuples for code blocks with language 'go'."""
    collected = []
    for block in blocks:
        if block.get("type") != "code":
            continue
        code_data = block.get("code", {})
        if code_data.get("language") != "go":
            continue
        code_plain = "".join(
            rt.get("plain_text", "") for rt in code_data.get("rich_text", [])
        )
        caption_plain = "".join(
            rt.get("plain_text", "") for rt in code_data.get("caption", [])
        )
        collected.append((code_plain, caption_plain))
    return collected


def verify(notion: Client, main_id: str | None = None) -> bool:
    page_id = _find_page(notion, main_id)
    if not page_id:
        print("Error: Target page not found.", file=sys.stderr)
        return False

    all_blocks = notion_utils.get_all_blocks_recursively(notion, page_id)

    # Verify header
    header_ok = any(_has_bold_header_text(b, HEADER_TEXT) for b in all_blocks)
    if not header_ok:
        print("Failure: Bold header 'Go' not found.", file=sys.stderr)
        return False

    # Verify code blocks
    code_blocks_found = _collect_code_blocks(all_blocks)

    remaining = EXPECTED_CODE_BLOCKS.copy()
    for code, caption in code_blocks_found:
        norm_code = _normalize(code)
        for expected in remaining:
            if (
                _normalize(expected["code"]) == norm_code
                and expected["caption"] == caption
            ):
                remaining.remove(expected)
                break
    if remaining:
        missing = ", ".join(exp["caption"] for exp in remaining)
        print(
            f"Failure: Missing or incorrect Go code blocks: {missing}", file=sys.stderr
        )
        return False

    # Verify column order Python → Go → JavaScript
    if not _go_column_order_correct(notion, page_id):
        print(
            "Failure: Go column is not positioned between Python and JavaScript.",
            file=sys.stderr,
        )
        return False

    print(
        "Success: Verified Go column with required code blocks and correct positioning."
    )
    return True


def main():
    notion = notion_utils.get_notion_client()
    main_id = sys.argv[1] if len(sys.argv) > 1 else None
    sys.exit(0 if verify(notion, main_id) else 1)


if __name__ == "__main__":
    main()
