"""Encoder coverage tests — targeting uncovered branches in encoder.py.

These tests specifically exercise the encoder paths that the existing
test_core.py misses, based on coverage analysis showing 67% coverage
with 210 uncovered statements.
"""

import pytest
from cdn import encode, encode_with_stats


class TestErrorEncoderBranches:
    """Cover all branches in _encode_error."""

    def test_error_with_timeout_keyword(self):
        result = encode("Error: timeout while processing")
        assert result.startswith("E:")
        assert "timeout" in result

    def test_error_with_auth(self):
        result = encode("Error: authentication failed for user")
        assert result.startswith("E:")
        assert "auth" in result

    def test_error_generic_5xx(self):
        result = encode("Error: the server failed unexpectedly")
        assert result.startswith("E:")
        assert "5xx" in result

    def test_error_with_retry_and_wait(self):
        result = encode("Error 503: retry 3 retries, wait for 30 seconds")
        assert result.startswith("E:")
        assert "503" in result
        assert "retry:3" in result
        assert "wait:30s" in result

    def test_error_with_wait_minutes(self):
        result = encode("Error: service failed, wait 5 minutes before trying again")
        assert result.startswith("E:")
        assert "wait:5m" in result

    def test_error_with_exponential_backoff(self):
        result = encode("Error 429: use exponential backoff")
        assert result.startswith("E:")
        assert "backoff:exp" in result

    def test_error_with_cache_fallback(self):
        result = encode("Error: API failed, use cache instead")
        assert result.startswith("E:")
        assert "fb:cache" in result

    def test_error_with_abort_fallback(self):
        result = encode("Error: data corrupted, abort and stop processing")
        assert result.startswith("E:")
        assert "fb:abort" in result

    def test_error_with_partial_fallback(self):
        result = encode("Error: some records failed, return what we have")
        assert result.startswith("E:")
        assert "fb:degrade" in result

    def test_error_negative_pattern_check_for_errors(self):
        """'check for errors' should NOT be encoded as error message."""
        result = encode("Check for errors in the log files")
        assert not result.startswith("E:"), f"Should not be error: {result}"

    def test_error_negative_pattern_handle_errors(self):
        result = encode("Handle errors gracefully in this module")
        assert not result.startswith("E:"), f"Should not be error: {result}"

    def test_error_negative_with_actual_code_overrides(self):
        """Negative pattern + actual error code = still an error."""
        result = encode("Check for errors, the API returned a 503")
        assert result.startswith("E:")
        assert "503" in result

    def test_error_negative_with_past_tense(self):
        """Negative pattern + 'failed' = still an error."""
        result = encode("Check for errors — the process already failed")
        assert result.startswith("E:")

    def test_error_specific_429(self):
        result = encode("Error: rate limited, returned a 429")
        assert result.startswith("E:")
        assert "429" in result


class TestCancelEncoderBranches:
    """Cover all branches in _encode_cancel."""

    def test_cancel_current(self):
        result = encode("Cancel the current task")
        assert result.startswith("X:")
        assert "current" in result

    def test_cancel_with_safe(self):
        result = encode("Cancel and ensure no side effects")
        assert result.startswith("X:")
        assert "safe:T" in result

    def test_cancel_with_no_side_effect_hyphen(self):
        result = encode("Cancel with no side-effect guarantee")
        assert result.startswith("X:")
        assert "safe:T" in result

    def test_cancel_with_ack(self):
        result = encode("Cancel all tasks and confirm cancellation")
        assert result.startswith("X:")
        assert "ack:T" in result

    def test_abort_triggers_cancel(self):
        result = encode("Abort all running processes")
        assert result.startswith("X:")


class TestStatusEncoderBranches:
    """Cover all branches in _encode_status."""

    def test_status_in_progress(self):
        result = encode("Processing is in progress")
        assert "#:" in result
        assert "run" in result

    def test_status_done_with_progress(self):
        result = encode("Task completed. 3 out of 10 stages done.")
        assert "#:" in result
        assert "done" in result
        assert "3/10" in result

    def test_status_with_records(self):
        result = encode("Task completed. 500 records processed.")
        assert "#:" in result
        assert "records:500" in result

    def test_status_with_items(self):
        result = encode("Processing done. 42 items written.")
        assert "#:" in result
        assert "items:42" in result

    def test_status_with_files(self):
        result = encode("Upload finished. 15 files uploaded.")
        assert "#:" in result
        assert "files:15" in result

    def test_status_with_time(self):
        result = encode("Processing completed in 3 seconds.")
        assert "#:" in result
        assert "time:3s" in result

    def test_status_with_time_ms(self):
        result = encode("Processing completed in 150 ms.")
        assert "#:" in result

    def test_status_with_percentage(self):
        result = encode("Processing complete. 95.5% accuracy achieved.")
        assert "#:" in result
        assert "pct:95.5" in result

    def test_status_with_output_path(self):
        result = encode("Processing done. Output saved to /tmp/results.csv")
        assert "#:" in result
        assert "out:/tmp/results.csv" in result

    def test_status_with_s3_path(self):
        result = encode("Processing done. Output at s3://bucket/key")
        assert "#:" in result
        assert "s3://bucket/key" in result

    def test_status_with_processed_verb(self):
        result = encode("Completed. 1000 processed successfully.")
        assert "#:" in result
        assert "processed:1000" in result

    def test_status_with_commas_in_numbers(self):
        result = encode("Processing done. 1,000,000 records.")
        assert "#:" in result
        assert "records:1000000" in result

    def test_status_finished_keyword(self):
        result = encode("Finished all stages successfully")
        assert "#:" in result
        assert "done" in result


class TestResultEncoderBranches:
    """Cover all branches in _encode_result."""

    def test_result_answer_is(self):
        result = encode("The answer is 42")
        assert result.startswith("=:")
        assert "42" in result

    def test_result_found_matches(self):
        result = encode("Found 7 matches in the dataset")
        assert result.startswith("=:")
        assert "found:7" in result

    def test_result_here_are(self):
        result = encode("Here are the results: alpha, beta, gamma")
        assert result.startswith("=:")

    def test_result_returning(self):
        result = encode("Returning the processed dataset")
        assert result.startswith("=:")

    def test_result_output_colon(self):
        result = encode("Output: processed_data.csv")
        assert result.startswith("=:")

    def test_result_not_triggered_by_search_for_results(self):
        """'search for results' is a command, not a result."""
        result = encode("Search for results matching the query")
        assert not result.startswith("=:"), f"Should not be result: {result}"

    def test_result_not_triggered_by_error(self):
        result = encode("Here are the results but error occurred")
        assert not result.startswith("=:")


class TestReceiveEncoderBranches:
    """Cover all branches in _encode_receive."""

    @pytest.mark.parametrize("ack_text", [
        "Acknowledged",
        "Received",
        "Got it",
        "Roger",
        "Roger that",
        "Understood",
        "Copy that",
        "OK",
        "Okay",
        "Affirmative",
        "Wilco",
        "10-4",
        "Confirmed",
    ])
    def test_ack_patterns(self, ack_text):
        result = encode(ack_text)
        assert "<:ack" in result, f"'{ack_text}' should encode to ack, got '{result}'"

    def test_ack_short_phrase(self):
        result = encode("Message received")
        assert "<:ack" in result

    def test_ack_task_acknowledged(self):
        result = encode("Task acknowledged")
        assert "<:ack" in result


class TestPolicyEncoderBranches:
    """Cover all branches in _encode_policy.

    Note: 'timeout' triggers the error encoder (which runs before policy),
    so policy timeout tests must use inputs where error encoder doesn't match.
    """

    def test_policy_retry(self):
        result = encode("Set default retry to 5 for all messages")
        assert "@:policy" in result
        assert "retry:5" in result

    def test_policy_fallback_degrade(self):
        result = encode("Always use degrade as fallback")
        assert "@:policy" in result
        assert "fb:degrade" in result

    def test_policy_backoff_exponential(self):
        result = encode("Set default retry 3 with exponential backoff for all messages")
        assert "@:policy" in result
        assert "backoff:exp" in result

    def test_policy_backoff_linear(self):
        result = encode("Set default retry 3 with backoff for all messages")
        assert "@:policy" in result
        assert "backoff:linear" in result

    def test_policy_always_retry(self):
        result = encode("Always retry 3 times before failing")
        assert "@:policy" in result
        assert "retry:3" in result


class TestCodeDefinitionBranches:
    """Cover all branches in _encode_code_definition."""

    def test_wire_pattern(self):
        result = encode("Wire dashboard to programs")
        assert "wire" in result
        assert "dashboard" in result

    def test_connect_pattern(self):
        result = encode("Connect auth to session")
        assert "wire" in result

    def test_wire_sync(self):
        result = encode("Wire dashboard to programs synchronously")
        assert "!?:" in result
        assert "wire" in result

    def test_when_fires_trigger(self):
        result = encode("When login fires, trigger refresh")
        assert "wire" in result
        assert "login" in result
        assert "refresh" in result

    def test_api_endpoint_post(self):
        result = encode("Define an API endpoint POST /users")
        assert "api" in result
        assert "POST" in result

    def test_api_endpoint_get(self):
        result = encode("Endpoint GET /health")
        assert "api" in result
        assert "GET" in result

    def test_schema_with_columns(self):
        result = encode("Define a schema orders with columns id, user_id, total")
        assert "schema" in result
        assert "orders" in result

    def test_table_with_fields(self):
        result = encode("Define table users with fields name, email, age")
        assert "schema" in result

    def test_type_with_fields(self):
        result = encode("Define a type User with fields name, email, age")
        assert "type" in result
        assert "User" in result

    def test_interface_with_properties(self):
        result = encode("Define interface Config with properties host, port, debug")
        assert "type" in result

    def test_component_accepts(self):
        result = encode("Define a component Sidebar that accepts items")
        assert "fn" in result
        assert "Sidebar" in result

    def test_function_takes(self):
        result = encode("Define function processData that takes input")
        assert "fn" in result

    def test_module_with_pages(self):
        result = encode("Define a module dashboard with pages home, settings")
        assert "def" in result
        assert "dashboard" in result

    def test_app_with_routes(self):
        result = encode("Define app myApp with routes login, dashboard, profile")
        assert "def" in result

    def test_assemble_with_target(self):
        result = encode("Assemble the final build")
        assert "asm" in result

    def test_assemble_bare(self):
        result = encode("Assemble")
        assert "asm" in result


class TestDelegationBranches:
    """Cover all branches in _encode_delegation."""

    def test_delegate_with_action(self):
        result = encode("Delegate to AgentC: review code")
        assert ">:" in result
        assert "AgentC" in result

    def test_forward_to(self):
        result = encode("Forward to AgentB: search news")
        assert ">:" in result
        assert "AgentB" in result

    def test_assign_to(self):
        result = encode("Assign to Worker1: process data")
        assert ">:" in result
        assert "Worker1" in result

    def test_route_to(self):
        result = encode("Route to Specialist: analyze results")
        assert ">:" in result

    def test_delegate_no_action_after_agent(self):
        result = encode("Delegate to AgentC")
        assert ">:" in result

    def test_send_to(self):
        result = encode("Send to AgentC: review the code")
        assert ">:" in result
        assert "AgentC" in result


class TestWorkflowBranches:
    """Cover workflow / multi-step encoder branches."""

    def test_workflow_three_steps(self):
        result = encode(
            "First, read the input. Then, transform it. Finally, write the output."
        )
        assert "seq(" in result

    def test_workflow_inline_eval_two_steps(self):
        """Two-step workflow should use [] inline evaluation."""
        result = encode("First, read the data. Then, summarize it.")
        assert "[" in result or "seq(" in result

    def test_workflow_with_sync(self):
        result = encode(
            "First read the data synchronously, then filter active records. "
            "After that, group by region."
        )
        assert "seq(" in result or "|" in result

    def test_workflow_next_keyword(self):
        result = encode(
            "First, search for data. Next, filter the results."
        )
        assert "seq(" in result or "[" in result or "|" in result


class TestParallelBranches:
    """Cover parallel dispatch encoder branches."""

    def test_parallel_with_task_labels(self):
        result = encode(
            "Execute in parallel: task 1: search news, task 2: translate text"
        )
        assert "par(" in result

    def test_parallel_numbered_list(self):
        result = encode(
            "Run simultaneously: 1) search news 2) summarize data 3) format output"
        )
        assert "par(" in result

    def test_parallel_with_merge(self):
        result = encode(
            "Execute in parallel: 1) search news 2) search blogs, then merge into single response"
        )
        assert "par(" in result
        assert "mrg" in result

    def test_parallel_concurrently(self):
        result = encode(
            "Concurrently: 1) translate to Spanish 2) summarize the text"
        )
        assert "par(" in result


class TestConditionalBranches:
    """Cover conditional encoder branches."""

    def test_conditional_basic(self):
        result = encode(
            "If it is a valid record, process it. If the record is invalid, log it."
        )
        assert "if(" in result

    def test_conditional_with_always(self):
        result = encode(
            "If it succeeds, store the result. If it fails, retry. In all cases, log the outcome."
        )
        assert "if(" in result
        assert "always" in result


class TestContextUpdateBranches:
    """Cover context update encoder branches."""

    def test_context_from_to(self):
        result = encode("Language changed from English to Spanish")
        assert "~:" in result

    def test_context_not_triggered_by_search(self):
        """'search' should prevent context_update from triggering."""
        result = encode("Search and update the results")
        assert not result.startswith("~:"), f"Should not be context update: {result}"


class TestPipelineCommandBranches:
    """Cover pipeline command encoder branches."""

    def test_and_then_pipeline(self):
        result = encode("Search for X and then summarize")
        assert "|" in result

    def test_followed_by_pipeline(self):
        result = encode("Filter records followed by sorting them")
        assert "|" in result

    def test_and_format_pipeline(self):
        result = encode("Search for data and format as JSON")
        assert "|" in result

    def test_and_sort_pipeline(self):
        result = encode("Filter active users and sort descending")
        assert "filt" in result

    def test_pipeline_not_triggered_with_workflow_keywords(self):
        """Should not trigger if 'first' is present (workflow takes precedence)."""
        result = encode("First search, then summarize, finally format")
        assert "seq(" in result or "[" in result


class TestSingleActionBranches:
    """Cover _encode_single_action helper branches."""

    def test_with_quoted_string(self):
        result = encode('Search for "machine learning" articles')
        assert "srch" in result
        assert "machine learning" in result

    def test_with_single_quoted_string(self):
        result = encode("Search for 'artificial intelligence' papers")
        assert "srch" in result

    def test_with_limit(self):
        result = encode("Search top 10 results")
        assert "/n:10" in result

    def test_with_count_match(self):
        result = encode("Search and return 5 items")
        assert "/n:5" in result

    def test_with_format_json(self):
        result = encode("Search for data in json format")
        assert "/fmt:json" in result

    def test_with_format_bullets(self):
        result = encode("Summarize in bullets")
        assert "/fmt:bullets" in result

    def test_with_language(self):
        result = encode("Translate to Spanish")
        assert "/lang:es" in result

    def test_with_language_french(self):
        result = encode("Translate into French")
        assert "/lang:fr" in result

    def test_with_sort_ascending(self):
        result = encode("Sort the records ascending")
        assert "/asc" in result

    def test_with_source_database(self):
        result = encode("Read records from the database")
        assert "/src:db" in result

    def test_with_source_api(self):
        result = encode("Read data from the api")
        assert "/src:api" in result

    def test_with_source_named(self):
        result = encode("Read data from the database users_table")
        assert "/src:db" in result

    def test_with_field_by(self):
        result = encode("Group records by region")
        assert "/by:region" in result

    def test_with_condition_where(self):
        result = encode("Filter where status is active")
        assert "/where:" in result
        assert "active" in result

    def test_condition_greater_than(self):
        result = encode("Filter where count greater than 100")
        assert "/where:" in result
        assert ">" in result

    def test_condition_less_than(self):
        result = encode("Filter where price less than 50")
        assert "/where:" in result
        assert "<" in result

    def test_with_url_path(self):
        result = encode("Read the file at /tmp/data.json")
        assert "/tmp/data.json" in result

    def test_with_fallback_cache(self):
        result = encode("Search for data, use cached_data if unavailable")
        assert "fb:cache" in result

    def test_with_fallback_skip(self):
        result = encode("Read data, use skip strategy")
        assert "fb:skip" in result

    def test_with_optional_safe_access(self):
        result = encode("Read metadata if available")
        assert "?" in result

    def test_adverb_each(self):
        result = encode("Summarize each document")
        assert "/each" in result

    def test_adverb_every(self):
        result = encode("Process every record in the set")
        assert "/each" in result

    def test_adverb_cumulative(self):
        result = encode("Calculate cumulative sum of values")
        assert "/scan" in result

    def test_adverb_running_total(self):
        result = encode("Compute running total of revenue")
        assert "/scan" in result

    def test_context_var_timestamp(self):
        result = encode("Log the current timestamp")
        assert "$t" in result

    def test_context_var_turn(self):
        result = encode("Log turn number in metadata")
        assert "$turn" in result

    def test_retry_with_times(self):
        result = encode("Retry the request 5 times")
        assert "retry" in result
        assert "/repeat:5" in result


class TestSyncDetection:
    """Cover _detect_sync branches."""

    def test_sync_wait_for_response(self):
        result = encode("Read data and wait for response")
        assert "!?:" in result

    def test_sync_blocking(self):
        result = encode("Execute blocking read of the database")
        assert "!?:" in result

    def test_sync_send_back(self):
        result = encode("Search and send back the results")
        assert "!?:" in result

    def test_sync_respond_immediately(self):
        result = encode("Execute and respond immediately")
        assert "!?:" in result


class TestCorrectionBranches:
    """Cover _encode_correction branches.

    The regex expects the pattern: section N: action (with colon separator).
    """

    def test_correction_with_sections(self):
        result = encode("Revision: section 1: keep, section 2: revise, section 3: remove")
        assert "~:^" in result
        assert "s1:keep" in result
        assert "s2:revise" in result
        assert "s3:del" in result

    def test_correction_ordinals(self):
        result = encode("Incorrect: section first: keep, section second: revise")
        assert "~:^" in result
        assert "s1:keep" in result
        assert "s2:revise" in result

    def test_correction_expand(self):
        result = encode("Wrong: section 2: expand")
        assert "~:^" in result
        assert "s2:revise+detail" in result


class TestFallbackEncoder:
    """Cover _encode_fallback — the last resort encoder."""

    def test_fallback_with_filler_words(self):
        result = encode("Hey, could you please just wanted to let you know something happened")
        assert isinstance(result, str)
        assert len(result) > 0
        assert result.startswith("!:")

    def test_fallback_pure_nonsense(self):
        result = encode("xyzzy plugh neither nor hither")
        assert result.startswith("!:exec")

    def test_fallback_empty_after_cleaning(self):
        result = encode("please could you")
        assert result.startswith("!:")

    def test_fallback_verb_in_cleaned(self):
        """Fallback should still find verbs after stripping filler."""
        result = encode("Hey, I need you to just search something")
        assert "srch" in result


class TestEncodeWithStatsV01:
    """Cover encode_with_stats v0.1 comparison fields."""

    def test_stats_has_v01_fields(self):
        stats = encode_with_stats("Search for news and summarize")
        assert "v01_equivalent" in stats
        assert "v01_tokens" in stats
        assert "v02_improvement_pct" in stats

    def test_v01_equivalent_is_valid(self):
        stats = encode_with_stats("First, read data. Then, filter active records.")
        assert isinstance(stats["v01_equivalent"], str)
        assert len(stats["v01_equivalent"]) > 0

    def test_v01_parallel(self):
        stats = encode_with_stats(
            "Run in parallel: 1) search news 2) translate text"
        )
        assert isinstance(stats["v01_equivalent"], str)


class TestUrgencyBranches:
    """Cover urgency detection edge cases."""

    def test_urgency_emergency(self):
        result = encode("EMERGENCY: shut down all services")
        assert "+++" in result

    def test_urgency_drop_everything(self):
        result = encode("Drop everything and deploy the fix")
        assert "+++" in result

    def test_urgency_immediately(self):
        result = encode("Search for the fix immediately")
        assert "++" in result

    def test_no_urgency(self):
        result = encode("Search for news when you have time")
        assert not result.startswith("+")
        assert not result.startswith("-")


class TestBulkContent:
    """Cover _detect_bulk_content."""

    def test_bulk_nested_json(self):
        result = encode('Write this data: {"users": {"admin": true}}')
        assert "<<<" in result or isinstance(result, str)

    def test_no_bulk_simple_text(self):
        result = encode("Search for news")
        assert "<<<" not in result
