# pylint: disable=line-too-long,useless-suppression
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) Python Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
import os
import uuid
import re
import json
from datetime import datetime
from typing import Optional, Dict, Any, List
import sys
from azure.ai.contentunderstanding.models import (
    ContentAnalyzer,
    ContentAnalyzerConfig,
    ContentFieldSchema,
    ContentFieldDefinition,
)
from azure.ai.contentunderstanding.models import GenerationMethod, ContentFieldType, ProcessingLocation

from devtools_testutils import is_live, is_live_and_not_recording


def generate_analyzer_id(client, test_name: str, is_async: bool = False) -> str:
    """Generate a unique analyzer ID using test name.

    Args:
        client: The ContentUnderstandingClient instance (not used, kept for compatibility)
        test_name: Short test identifier
        is_async: If True, uses 'async' prefix; if False, uses 'sync' prefix

    Returns:
        str: A unique analyzer ID (format: python_sdk_{sync|async}_{test_name})
    """
    prefix = "async" if is_async else "sync"
    analyzer_id = f"python_sdk_{prefix}_{test_name}"
    return analyzer_id


def new_simple_content_analyzer_object(
    analyzer_id: str, description: Optional[str] = None, tags: Optional[Dict[str, str]] = None
) -> ContentAnalyzer:
    """Create a simple ContentAnalyzer object with default configuration.

    Args:
        analyzer_id: The analyzer ID
        description: Optional description for the analyzer
        tags: Optional tags for the analyzer

    Returns:
        ContentAnalyzer: A configured ContentAnalyzer object
    """
    if description is None:
        description = f"test analyzer: {analyzer_id}"
    if tags is None:
        tags = {"test_type": "simple"}

    return ContentAnalyzer(
        base_analyzer_id="prebuilt-document",
        config=ContentAnalyzerConfig(
            enable_formula=True,
            enable_layout=True,
            enable_ocr=True,
            estimate_field_source_and_confidence=True,
            return_details=True,
        ),
        description=description,
        field_schema=ContentFieldSchema(
            fields={
                "amount_due": ContentFieldDefinition(
                    description="Total amount due of this table",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.NUMBER,
                )
            },
            description="schema description here",
            name="schema name here",
        ),
        processing_location=ProcessingLocation.GLOBAL,
        models={"completion": "gpt-4.1"},  # Required when using field_schema
        tags=tags,
    )


def new_marketing_video_analyzer_object(
    analyzer_id: str, description: Optional[str] = None, tags: Optional[Dict[str, str]] = None
) -> ContentAnalyzer:
    """Create a marketing video ContentAnalyzer object based on the marketing video template.

    Args:
        analyzer_id: The analyzer ID
        description: Optional description for the analyzer
        tags: Optional tags for the analyzer

    Returns:
        ContentAnalyzer: A configured ContentAnalyzer object for video analysis
    """
    if description is None:
        description = f"marketing video analyzer: {analyzer_id}"
    if tags is None:
        tags = {"test_type": "marketing_video"}

    return ContentAnalyzer(
        base_analyzer_id="prebuilt-video",
        config=ContentAnalyzerConfig(
            return_details=True,
        ),
        description=description,
        processing_location=ProcessingLocation.GLOBAL,
        models={"completion": "gpt-4.1"},  # Required when using field_schema
        tags=tags,
    )


def assert_poller_properties(poller: Any, poller_name: str = "Poller") -> None:
    """Assert common poller properties for any LROPoller or AsyncLROPoller.

    Args:
        poller: The LROPoller or AsyncLROPoller instance to validate
        poller_name: Optional name for the poller in log messages

    Raises:
        AssertionError: If any poller property assertion fails
    """
    assert poller is not None, f"{poller_name} should not be None"
    assert poller.status() is not None, f"{poller_name} status should not be None"
    assert poller.status() != "", f"{poller_name} status should not be empty"
    assert poller.continuation_token() is not None, f"{poller_name} continuation_token should not be None"
    print(f"{poller_name} properties verified successfully")


def assert_simple_content_analyzer_result(analysis_result: Any, result_name: str = "Analysis result") -> None:
    """Assert simple content analyzer result properties and field extraction.

    Args:
        analysis_result: The analysis result object to validate
        result_name: Optional name for the result in log messages

    Raises:
        AssertionError: If any analysis result property assertion fails
    """
    print(f"Validating {result_name} properties")
    assert analysis_result is not None, f"{result_name} should not be None"
    assert (
        analysis_result.__class__.__name__ == "AnalysisResult"
    ), f"{result_name} should be AnalysisResult, got {analysis_result.__class__.__name__}"
    assert analysis_result.contents is not None, f"{result_name} should have contents"
    assert len(analysis_result.contents) > 0, f"{result_name} should have at least one content"

    print(f"{result_name} properties verified successfully")

    # Verify fields node exists in the first result of contents

    first_content = analysis_result.contents[0]
    assert hasattr(first_content, "fields"), "First content should have fields"
    print(f"Verified fields node exists in first result")

    # Verify amount_due field exists and equals 610.0
    fields = first_content.fields

    # Fields is expected to be a dictionary
    assert isinstance(fields, dict), f"Fields should be a dictionary, got {type(fields)}"
    assert "amount_due" in fields, f"Fields should contain amount_due. Available fields: {list(fields.keys())}"

    amount_due_field = fields["amount_due"]
    assert amount_due_field is not None, "amount_due field should not be None"
    assert (
        amount_due_field.__class__.__name__ == "NumberField"
    ), f"amount_due field should be of type NumberField, got {amount_due_field.__class__.__name__}"

    amount_due_value = amount_due_field.value

    print(f"Total amount field value: {amount_due_value}")
    assert amount_due_value == 610.0, f"Expected amount_due to be 610.0, but got {amount_due_value}"
    print(f"Total amount field validation successful")


def save_analysis_result_to_file(
    analysis_result: Any,
    test_name: str,
    test_py_file_dir: str,
    identifier: Optional[str] = None,
    output_dir: str = "test_output",
) -> str:
    """Save analysis result to output file using pytest naming convention.

    Args:
        analysis_result: The analysis result object to save
        test_name: Name of the test case (e.g., function name)
        test_py_file_dir: Directory where pytest files are located
        identifier: Optional unique identifier for the result (e.g., analyzer_id)
        output_dir: Directory name to save the output file (default: "test_output")

    Returns:
        str: Path to the saved output file

    Raises:
        OSError: If there are issues creating directory or writing file
    """
    # Create output directory if it doesn't exist
    output_dir_path = os.path.join(test_py_file_dir, output_dir)
    os.makedirs(output_dir_path, exist_ok=True)

    # Generate output filename with timestamp
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    # Build filename with test name and optional identifier
    if identifier:
        output_filename = f"{test_name}_{identifier}_{timestamp}.json"
    else:
        output_filename = f"{test_name}_{timestamp}.json"

    saved_file_path = os.path.join(output_dir_path, output_filename)

    # Save the analysis result
    with open(saved_file_path, "w") as output_file:
        json.dump(analysis_result.as_dict(), output_file, indent=2)

    print(f"Analysis result saved to: {saved_file_path}")
    return saved_file_path


def save_keyframe_image_to_file(
    image_content: bytes,
    keyframe_id: str,
    test_name: str,
    test_py_file_dir: str,
    identifier: Optional[str] = None,
    output_dir: str = "test_output",
) -> str:
    """Save keyframe image to output file using pytest naming convention.

    Args:
        image_content: The binary image content to save
        keyframe_id: The keyframe ID (e.g., "keyframes/733")
        test_name: Name of the test case (e.g., function name)
        test_py_file_dir: Directory where pytest files are located
        identifier: Optional unique identifier to avoid conflicts (e.g., analyzer_id)
        output_dir: Directory name to save the output file (default: "test_output")

    Returns:
        str: Path to the saved image file

    Raises:
        OSError: If there are issues creating directory or writing file
    """
    # Generate timestamp and frame ID
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    # Extract the frame time from the keyframe path (e.g., "keyframes/733" -> "733")
    if "/" in keyframe_id:
        frame_id = keyframe_id.split("/")[-1]
    else:
        # Fallback: use as-is if no slash found
        frame_id = keyframe_id

    # Create output directory if it doesn't exist
    output_dir_path = os.path.join(test_py_file_dir, output_dir)
    os.makedirs(output_dir_path, exist_ok=True)

    # Generate output filename with optional identifier to avoid conflicts
    if identifier:
        output_filename = f"{test_name}_{identifier}_{timestamp}_{frame_id}.jpg"
    else:
        output_filename = f"{test_name}_{timestamp}_{frame_id}.jpg"

    saved_file_path = os.path.join(output_dir_path, output_filename)

    # Write the image content to file
    with open(saved_file_path, "wb") as image_file:
        image_file.write(image_content)

    print(f"Image file saved to: {saved_file_path}")
    return saved_file_path


def read_image_bytes(image_path: str) -> bytes:
    """Read image file and return raw bytes.

    Args:
        image_path: Path to the image file

    Returns:
        bytes: Raw image data as bytes

    Raises:
        FileNotFoundError: If the image file doesn't exist
        OSError: If there are issues reading the file
    """
    with open(image_path, "rb") as image_file:
        return image_file.read()


def get_test_data_path(relative_path: str) -> str:
    """Get the absolute path to test data files.

    Args:
        relative_path: Relative path from the test data directory

    Returns:
        str: Absolute path to the test data file
    """
    test_file_dir = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(test_file_dir, "test_data", relative_path)


def assert_document_properties(analysis_result: Any, expected_min_pages: int = 1) -> None:
    """Assert document-level properties from analysis result.

    Validates that the analysis result contains expected document properties such as:
    - Page count
    - Content structure (pages, paragraphs, etc.)
    - OCR results if enabled
    - Layout information

    Args:
        analysis_result: The analysis result object to validate
        expected_min_pages: Minimum expected number of pages (default: 1)

    Raises:
        AssertionError: If any document property assertion fails
    """
    print(f"Validating document properties")

    assert analysis_result is not None, "Analysis result should not be None"
    assert analysis_result.contents is not None, "Analysis result should have contents"
    assert len(analysis_result.contents) > 0, "Analysis result should have at least one content item"

    # Verify the first content has expected structure
    first_content = analysis_result.contents[0]
    assert first_content is not None, "First content should not be None"

    # Check if markdown content is present (most common output format)
    if hasattr(first_content, "markdown") and first_content.markdown:
        markdown_content = first_content.markdown
        assert isinstance(markdown_content, str), "Markdown content should be a string"
        assert len(markdown_content) > 0, "Markdown content should not be empty"
        print(f"✓ Markdown content found: {len(markdown_content)} characters")

    # Check pages information if available
    if hasattr(first_content, "pages") and first_content.pages:
        pages = first_content.pages
        assert len(pages) >= expected_min_pages, f"Expected at least {expected_min_pages} page(s), got {len(pages)}"
        print(f"✓ Document has {len(pages)} page(s)")

        # Validate first page properties
        first_page = pages[0]
        if hasattr(first_page, "page_number"):
            assert first_page.page_number >= 1, "Page number should be >= 1"
            print(f"✓ First page number: {first_page.page_number}")

    # Check if fields were extracted (if using field schema)
    if hasattr(first_content, "fields") and first_content.fields:
        fields = first_content.fields
        assert isinstance(fields, dict), "Fields should be a dictionary"
        print(f"✓ Extracted {len(fields)} field(s): {list(fields.keys())}")

        # Validate each field has value
        for field_name, field_value in fields.items():
            assert field_value is not None, f"Field '{field_name}' should have a value"

    print(f"✓ Document properties validation completed successfully")


def new_invoice_analyzer_object(
    analyzer_id: str, description: Optional[str] = None, tags: Optional[Dict[str, str]] = None
) -> ContentAnalyzer:
    """Create an invoice ContentAnalyzer object with comprehensive field extraction schema.

    This analyzer is configured to extract common invoice fields including:
    - invoice_number: The invoice number or ID
    - invoice_date: The date the invoice was issued
    - due_date: The payment due date
    - vendor_name: The name of the vendor/seller
    - vendor_address: The vendor's address
    - customer_name: The name of the customer/buyer
    - customer_address: The customer's address
    - subtotal: The subtotal amount before tax
    - tax_amount: The tax amount
    - amount_due: The total amount due

    Args:
        analyzer_id: The analyzer ID
        description: Optional description for the analyzer
        tags: Optional tags for the analyzer

    Returns:
        ContentAnalyzer: A configured ContentAnalyzer object for invoice analysis
    """
    if description is None:
        description = f"invoice analyzer: {analyzer_id}"
    if tags is None:
        tags = {"test_type": "invoice_analysis"}

    return ContentAnalyzer(
        base_analyzer_id="prebuilt-document",
        config=ContentAnalyzerConfig(
            enable_formula=True,
            enable_layout=True,
            enable_ocr=True,
            estimate_field_source_and_confidence=True,
            return_details=True,
        ),
        description=description,
        field_schema=ContentFieldSchema(
            fields={
                "invoice_number": ContentFieldDefinition(
                    description="The invoice number or ID",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "invoice_date": ContentFieldDefinition(
                    description="The date the invoice was issued",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "due_date": ContentFieldDefinition(
                    description="The payment due date",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "vendor_name": ContentFieldDefinition(
                    description="The name of the vendor or seller",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "vendor_address": ContentFieldDefinition(
                    description="The address of the vendor",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "customer_name": ContentFieldDefinition(
                    description="The name of the customer or buyer",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "customer_address": ContentFieldDefinition(
                    description="The address of the customer",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.STRING,
                ),
                "subtotal": ContentFieldDefinition(
                    description="The subtotal amount before tax",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.NUMBER,
                ),
                "tax_amount": ContentFieldDefinition(
                    description="The tax amount",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.NUMBER,
                ),
                "amount_due": ContentFieldDefinition(
                    description="The total amount due",
                    method=GenerationMethod.EXTRACT,
                    type=ContentFieldType.NUMBER,
                ),
            },
            description="Invoice field extraction schema",
            name="invoice_schema",
        ),
        processing_location=ProcessingLocation.GLOBAL,
        models={"completion": "gpt-4.1"},  # Required when using field_schema
        tags=tags,
    )


def assert_invoice_fields(analysis_result: Any, result_name: str = "Invoice analysis result") -> None:
    """Assert invoice-specific field extraction from analysis result.

    Validates that the analysis result contains expected invoice fields and their properties:
    - Fields are present and have values
    - Numeric fields (amount_due, subtotal, tax_amount) have correct types
    - String fields (invoice_number, dates, names) are non-empty
    - Confidence scores are present
    - Source/span information is available

    Args:
        analysis_result: The analysis result object to validate
        result_name: Optional name for the result in log messages

    Raises:
        AssertionError: If any invoice field assertion fails
    """
    print(f"Validating {result_name} invoice fields")

    assert analysis_result is not None, f"{result_name} should not be None"
    assert analysis_result.contents is not None, f"{result_name} should have contents"
    assert len(analysis_result.contents) > 0, f"{result_name} should have at least one content item"

    first_content = analysis_result.contents[0]
    assert first_content is not None, "First content should not be None"

    # Verify fields were extracted
    assert hasattr(first_content, "fields"), "Content should have fields attribute"
    assert first_content.fields is not None, "Fields should not be None"
    fields = first_content.fields
    assert isinstance(fields, dict), "Fields should be a dictionary"
    assert len(fields) > 0, "Should have extracted at least one field"

    print(f"✓ Extracted {len(fields)} invoice field(s): {list(fields.keys())}")

    # Define expected invoice fields (at least some should be present)
    expected_fields = [
        "invoice_number",
        "invoice_date",
        "due_date",
        "vendor_name",
        "vendor_address",
        "customer_name",
        "customer_address",
        "subtotal",
        "tax_amount",
        "amount_due",
    ]

    found_fields = [f for f in expected_fields if f in fields]
    print(f"✓ Found {len(found_fields)} expected invoice fields: {found_fields}")

    # Validate numeric fields if present
    numeric_fields = ["amount_due", "subtotal", "tax_amount"]
    for field_name in numeric_fields:
        if field_name in fields:
            field_value = fields[field_name]
            assert field_value is not None, f"Field '{field_name}' should have a value"

            # Check if it's a dict with 'valueNumber' (common response format)
            if isinstance(field_value, dict):
                assert "type" in field_value, f"Field '{field_name}' should have a type"
                assert field_value["type"] == "number", f"Field '{field_name}' should have type 'number'"

                if "valueNumber" in field_value:
                    value = field_value["valueNumber"]
                    assert isinstance(value, (int, float)), f"Field '{field_name}' valueNumber should be numeric"
                    assert value >= 0, f"Field '{field_name}' value should be non-negative"
                    print(f"✓ {field_name}: {value}")

                # Check confidence if available
                if "confidence" in field_value:
                    confidence = field_value["confidence"]
                    assert isinstance(confidence, (int, float)), f"Confidence should be numeric"
                    assert 0 <= confidence <= 1, f"Confidence should be between 0 and 1"
                    print(f"  - Confidence: {confidence:.2%}")

                # Check spans/source if available
                if "spans" in field_value:
                    spans = field_value["spans"]
                    assert isinstance(spans, list), "Spans should be a list"
                    assert len(spans) > 0, "Should have at least one span"
                    print(f"  - Source spans: {len(spans)} location(s)")

    # Validate string fields if present
    string_fields = ["invoice_number", "vendor_name", "customer_name"]
    for field_name in string_fields:
        if field_name in fields:
            field_value = fields[field_name]
            assert field_value is not None, f"Field '{field_name}' should have a value"

            # Check if it's a dict with 'valueString' (common response format)
            if isinstance(field_value, dict):
                assert "type" in field_value, f"Field '{field_name}' should have a type"
                assert field_value["type"] == "string", f"Field '{field_name}' should have type 'string'"

                if "valueString" in field_value:
                    value = field_value["valueString"]
                    assert isinstance(value, str), f"Field '{field_name}' valueString should be string"
                    assert len(value) > 0, f"Field '{field_name}' value should not be empty"
                    print(f"✓ {field_name}: {value}")

    print(f"✓ Invoice fields validation completed successfully")
