import asyncio
import logging
from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from cintes import gestiona_estat_cinta  # Ajusta el nom del mòdul segons la teva estructura


@pytest.mark.asyncio
async def test_gestiona_estat_cinta_respon_ok_per_linia():
    """Test que verifica que gestiona_estat_cinta respon d'acord amb el protocol."""
    # Configuració del mock de StreamReader
    missatges = [
        "ID cinta_1\n".encode(),
        "VELOCITAT 3.7\n".encode(),
        "VELOCITAT 0\n".encode(),
        "AVARIA\n".encode(),
        "VELOCITAT 0\n".encode(),
        "VELOCITAT 10\n".encode(),
        b"",  # Senyal d'EOF
    ]
    reader = AsyncMock()
    reader.readline = AsyncMock(side_effect=missatges)

    # Configuració del mock de StreamWriter
    writer = MagicMock()
    writer.write = MagicMock()
    writer.drain = AsyncMock()
    writer.close = MagicMock()
    writer.wait_closed = AsyncMock()

    # Execució de la corutina
    await gestiona_estat_cinta({}, reader, writer)

    # Verificacions
    assert writer.write.call_count == len(missatges) - 1 # Una vegada per línia
    calls = writer.write.call_args_list
    assert calls[0][0][0] == b"OK cinta_1\n"  # Primera resposta
    assert calls[1][0][0] == b"OK MOVIMENT\n"  # Segona resposta
    assert calls[2][0][0] == b"OK ATURADA\n"  # Segona resposta
    assert calls[3][0][0] == b"OK AVARIADA\n"  # Segona resposta
    assert calls[4][0][0] == b"OK ATURADA\n"  # Segona resposta
    assert calls[5][0][0] == b"OK MOVIMENT\n"  # Segona resposta

    # Verificar que s'ha cridat drain després de cada write
    assert writer.drain.call_count == len(missatges) - 1

    # Verificar tancament del writer
    writer.close.assert_called_once()
    writer.drain.assert_called()  # Comprovació addicional que drain es crida abans de close


@pytest.mark.asyncio
async def test_gestiona_estat_cinta_tanca_writer_en_excepcio():
    """Test que verifica que gestiona_estat_cinta tanca el writer en cas d'excepció."""
    # Configuració del mock de StreamReader per llançar una excepció
    reader = AsyncMock()
    reader.readline = AsyncMock(side_effect=Exception("Error de lectura"))

    # Configuració del mock de StreamWriter
    writer = MagicMock()
    writer.write = MagicMock()
    writer.drain = AsyncMock()
    writer.close = MagicMock()
    writer.wait_closed = AsyncMock()

    # Mock del registre d'excepcions
    with patch('logging.exception') as mock_log:
        await gestiona_estat_cinta({}, reader, writer)

    # Verificacions
    writer.close.assert_called_once()
    mock_log.assert_called_once_with("Excepció en gestiona_estat_cinta", exc_info=True)
