"""
Tests for pyiwfm.io.preprocessor_writer module.

Tests the PreProcessorWriter class and standalone file writing functions.
"""

from __future__ import annotations

from pathlib import Path
from unittest.mock import MagicMock, patch

import numpy as np
import pytest

from pyiwfm.io.config import PreProcessorFileConfig
from pyiwfm.io.preprocessor_writer import (
    PreProcessorWriter,
    write_elements_file,
    write_nodes_file,
    write_preprocessor_files,
    write_stratigraphy_file,
)


class TestPreProcessorWriterInit:
    """Tests for PreProcessorWriter initialization."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock IWFMModel."""
        model = MagicMock()
        model.name = "Test Model"
        model.n_nodes = 10
        model.n_elements = 5
        model.has_streams = False
        model.has_lakes = False
        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create a preprocessor file config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "output")

    def test_init_basic(self, mock_model: MagicMock, config: PreProcessorFileConfig) -> None:
        """Test basic initialization."""
        writer = PreProcessorWriter(mock_model, config)
        assert writer.model is mock_model
        assert writer.config is config
        assert writer.format == "iwfm_preprocessor"

    def test_init_custom_template_engine(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test initialization with custom template engine."""
        from pyiwfm.templates.engine import TemplateEngine

        engine = TemplateEngine()
        writer = PreProcessorWriter(mock_model, config, template_engine=engine)
        assert writer._engine is engine


class TestPreProcessorWriterWriteNodes:
    """Tests for write_nodes method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model with grid."""
        model = MagicMock()
        model.n_nodes = 4

        # Create mock nodes
        nodes = {}
        for i in range(1, 5):
            node = MagicMock()
            node.x = float(i * 100)
            node.y = float(i * 200)
            nodes[i] = node

        model.grid.nodes = nodes
        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_nodes_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_nodes creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_nodes()
        assert path.exists()

    def test_write_nodes_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_nodes file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_nodes()

        content = path.read_text()
        assert "NNODES" in content
        assert "FACTXY" in content
        assert "4" in content  # n_nodes
        assert "100.000000" in content  # node 1 x
        assert "200.000000" in content  # node 1 y

    def test_write_nodes_header(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_nodes has proper header."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_nodes()

        content = path.read_text()
        assert "IWFM NODAL COORDINATES FILE" in content
        assert "Generated by pyiwfm" in content


class TestPreProcessorWriterWriteElements:
    """Tests for write_elements method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model with elements."""
        model = MagicMock()
        model.n_elements = 3

        # Create mock elements
        elements = {}
        for i in range(1, 4):
            elem = MagicMock()
            elem.vertices = [i, i + 1, i + 2, i + 3]
            elem.subregion = 1
            elements[i] = elem

        model.grid.elements = elements
        # Create proper subregion object with name attribute as string
        sr1 = MagicMock()
        sr1.name = "Region 1"
        model.grid.subregions = {1: sr1}
        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_elements_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_elements creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_elements()
        assert path.exists()

    def test_write_elements_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_elements file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_elements()

        content = path.read_text()
        assert "NELEM" in content
        assert "NSUBREGION" in content
        assert "3" in content  # n_elements

    def test_write_elements_with_multiple_subregions(self, config: PreProcessorFileConfig) -> None:
        """Test write_elements with multiple subregions."""
        model = MagicMock()
        model.n_elements = 3

        elements = {}
        subregion_ids = [1, 2, 1]  # Elements in different subregions
        for i, sr in zip(range(1, 4), subregion_ids, strict=False):
            elem = MagicMock()
            elem.vertices = [i, i + 1, i + 2, 0]  # Triangle
            elem.subregion = sr
            elements[i] = elem

        model.grid.elements = elements
        model.grid.subregions = {}

        writer = PreProcessorWriter(model, config)
        path = writer.write_elements()

        content = path.read_text()
        assert "2" in content  # n_subregions = 2

    def test_write_elements_triangles(self, config: PreProcessorFileConfig) -> None:
        """Test write_elements handles triangular elements."""
        model = MagicMock()
        model.n_elements = 1

        elem = MagicMock()
        elem.vertices = [1, 2, 3]  # Only 3 vertices
        elem.subregion = 1

        model.grid.elements = {1: elem}
        model.grid.subregions = {}

        writer = PreProcessorWriter(model, config)
        path = writer.write_elements()

        content = path.read_text()
        lines = content.strip().split("\n")
        # Last line should have element data with vertex 4 = 0
        data_lines = [line for line in lines if not line.strip().startswith("C") and line.strip()]
        # Find line with element 1 vertices
        for line in data_lines:
            parts = line.split()
            if len(parts) >= 6 and parts[0] == "1":
                assert parts[4] == "0"  # Fourth vertex should be 0


class TestPreProcessorWriterWriteStratigraphy:
    """Tests for write_stratigraphy method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model with stratigraphy."""
        model = MagicMock()
        model.n_nodes = 3

        # Mock stratigraphy
        strat = MagicMock()
        strat.n_layers = 2
        strat.gs_elev = np.array([100.0, 110.0, 120.0])
        strat.top_elev = np.array([[90.0, 70.0], [100.0, 80.0], [110.0, 90.0]])
        strat.bottom_elev = np.array([[70.0, 50.0], [80.0, 60.0], [90.0, 70.0]])
        model.stratigraphy = strat

        # Mock grid nodes
        nodes = {i: MagicMock() for i in range(1, 4)}
        model.grid.nodes = nodes

        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_stratigraphy_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_stratigraphy creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_stratigraphy()
        assert path.exists()

    def test_write_stratigraphy_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_stratigraphy file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_stratigraphy()

        content = path.read_text()
        assert "NLAYERS" in content
        assert "FACTEL" in content
        assert "2" in content  # n_layers

    def test_write_stratigraphy_thickness_format(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that stratigraphy is written in thickness format."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_stratigraphy()

        content = path.read_text()
        # Should have columns for aquitard and aquifer thicknesses
        assert "AQT_L1" in content or "GSELEV" in content


class TestPreProcessorWriterWriteMain:
    """Tests for write_main method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model."""
        model = MagicMock()
        model.name = "Test Model"
        model.has_streams = False
        model.has_lakes = False
        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_main_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_main creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_main()
        assert path.exists()

    def test_write_main_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_main file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_main()

        content = path.read_text()
        assert "INTEGRATED WATER FLOW MODEL" in content
        assert "BINARY OUTPUT" in content
        assert "ELEMENT CONFIGURATION FILE" in content
        assert "NODE X-Y COORDINATE FILE" in content
        assert "STRATIGRAPHIC DATA FILE" in content

    def test_write_main_with_streams(self, config: PreProcessorFileConfig) -> None:
        """Test write_main with streams enabled."""
        model = MagicMock()
        model.name = "Test Model"
        model.has_streams = True
        model.has_lakes = False

        writer = PreProcessorWriter(model, config)
        path = writer.write_main()

        content = path.read_text()
        assert "STREAM GEOMETRIC DATA FILE" in content


class TestPreProcessorWriterWriteStreamConfig:
    """Tests for write_stream_config method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model with streams."""
        model = MagicMock()
        model.has_streams = True

        # Mock stream reaches
        reach = MagicMock()
        reach.id = 1
        reach.upstream_node = 100
        reach.downstream_node = 200
        reach.outflow_reach = 0

        # Mock stream nodes
        stream_node = MagicMock()
        stream_node.id = 1
        stream_node.gw_node = 50
        stream_node.reach_id = 1
        stream_node.stage = 10.0

        streams = MagicMock()
        streams.iter_reaches.return_value = [reach]
        streams.iter_nodes.return_value = [stream_node]
        model.streams = streams

        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_stream_config_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_stream_config creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_stream_config()
        assert path.exists()

    def test_write_stream_config_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_stream_config file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_stream_config()

        content = path.read_text()
        assert "STREAM CONFIGURATION FILE" in content
        assert "NREACH" in content
        assert "NSTRMNODE" in content

    def test_write_stream_config_no_streams(self, config: PreProcessorFileConfig) -> None:
        """Test write_stream_config with no streams."""
        model = MagicMock()
        model.streams = None

        writer = PreProcessorWriter(model, config)
        path = writer.write_stream_config()

        content = path.read_text()
        assert "0" in content  # NREACH = 0


class TestPreProcessorWriterWriteLakeConfig:
    """Tests for write_lake_config method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model with lakes."""
        model = MagicMock()
        model.has_lakes = True

        # Mock lake
        lake = MagicMock()
        lake.id = 1
        lake.name = "Test Lake"
        lake.elements = [10, 11, 12]

        lakes = MagicMock()
        lakes.iter_lakes.return_value = [lake]
        model.lakes = lakes

        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_lake_config_creates_file(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_lake_config creates a file."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_lake_config()
        assert path.exists()

    def test_write_lake_config_content(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_lake_config file content."""
        writer = PreProcessorWriter(mock_model, config)
        path = writer.write_lake_config()

        content = path.read_text()
        assert "LAKE CONFIGURATION FILE" in content
        assert "NLAKES" in content
        assert "LAKEID" in content

    def test_write_lake_config_no_lakes(self, config: PreProcessorFileConfig) -> None:
        """Test write_lake_config with no lakes."""
        model = MagicMock()
        model.lakes = None

        writer = PreProcessorWriter(model, config)
        path = writer.write_lake_config()

        content = path.read_text()
        # Should have NLAKES = 0
        lines = content.split("\n")
        nlakes_line = [
            line for line in lines if "NLAKES" in line and not line.strip().startswith("C")
        ]
        assert len(nlakes_line) > 0
        assert "0" in nlakes_line[0]


class TestPreProcessorWriterWriteAll:
    """Tests for write_all method."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a complete mock model."""
        model = MagicMock()
        model.name = "Test Model"
        model.n_nodes = 4
        model.n_elements = 2
        model.has_streams = False
        model.has_lakes = False

        # Mock grid
        nodes = {i: MagicMock(x=float(i * 100), y=float(i * 200)) for i in range(1, 5)}
        elements = {}
        for i in range(1, 3):
            elem = MagicMock()
            elem.vertices = [i, i + 1, i + 2, i + 3]
            elem.subregion = 1
            elements[i] = elem

        model.grid.nodes = nodes
        model.grid.elements = elements
        model.grid.subregions = {}

        # Mock stratigraphy
        strat = MagicMock()
        strat.n_layers = 1
        strat.gs_elev = np.array([100.0, 110.0, 120.0, 130.0])
        strat.top_elev = np.array([[90.0], [100.0], [110.0], [120.0]])
        strat.bottom_elev = np.array([[70.0], [80.0], [90.0], [100.0]])
        model.stratigraphy = strat

        return model

    @pytest.fixture
    def config(self, tmp_path: Path) -> PreProcessorFileConfig:
        """Create config."""
        return PreProcessorFileConfig(output_dir=tmp_path / "preprocessor")

    def test_write_all_creates_files(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write_all creates all files."""
        writer = PreProcessorWriter(mock_model, config)
        results = writer.write_all()

        assert "nodes" in results
        assert "elements" in results
        assert "stratigraphy" in results
        assert "main" in results

        for path in results.values():
            assert path.exists()

    def test_write_all_with_streams(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_all with streams."""
        mock_model.has_streams = True
        mock_model.streams = MagicMock()
        mock_model.streams.iter_reaches.return_value = []
        mock_model.streams.iter_nodes.return_value = []

        writer = PreProcessorWriter(mock_model, config)
        results = writer.write_all()

        assert "stream_config" in results
        assert results["stream_config"].exists()

    def test_write_all_with_lakes(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test write_all with lakes."""
        mock_model.has_lakes = True
        mock_model.lakes = MagicMock()
        mock_model.lakes.iter_lakes.return_value = []

        writer = PreProcessorWriter(mock_model, config)
        results = writer.write_all()

        assert "lake_config" in results
        assert results["lake_config"].exists()

    def test_write_method_calls_write_all(
        self, mock_model: MagicMock, config: PreProcessorFileConfig
    ) -> None:
        """Test that write() calls write_all()."""
        writer = PreProcessorWriter(mock_model, config)
        with patch.object(writer, "write_all") as mock_write_all:
            writer.write()
            mock_write_all.assert_called_once()


class TestWritePreprocessorFiles:
    """Tests for write_preprocessor_files convenience function."""

    @pytest.fixture
    def mock_model(self) -> MagicMock:
        """Create a mock model."""
        model = MagicMock()
        model.name = "Test"
        model.n_nodes = 2
        model.n_elements = 1
        model.has_streams = False
        model.has_lakes = False

        nodes = {1: MagicMock(x=0.0, y=0.0), 2: MagicMock(x=100.0, y=100.0)}
        elem = MagicMock()
        elem.vertices = [1, 2, 1, 2]
        elem.subregion = 1

        model.grid.nodes = nodes
        model.grid.elements = {1: elem}
        model.grid.subregions = {}

        strat = MagicMock()
        strat.n_layers = 1
        strat.gs_elev = np.array([100.0, 110.0])
        strat.top_elev = np.array([[90.0], [100.0]])
        strat.bottom_elev = np.array([[70.0], [80.0]])
        model.stratigraphy = strat

        return model

    def test_write_preprocessor_files(self, mock_model: MagicMock, tmp_path: Path) -> None:
        """Test write_preprocessor_files function."""
        results = write_preprocessor_files(mock_model, tmp_path / "output")

        assert "main" in results
        assert "nodes" in results
        assert "elements" in results
        assert "stratigraphy" in results

    def test_write_preprocessor_files_with_versions(
        self, mock_model: MagicMock, tmp_path: Path
    ) -> None:
        """Test write_preprocessor_files with version parameters."""
        mock_model.has_streams = True
        mock_model.has_lakes = True
        mock_model.streams = MagicMock()
        mock_model.streams.iter_reaches.return_value = []
        mock_model.streams.iter_nodes.return_value = []
        mock_model.lakes = MagicMock()
        mock_model.lakes.iter_lakes.return_value = []

        results = write_preprocessor_files(
            mock_model,
            tmp_path / "output",
            stream_version="5.0",
            lake_version="5.0",
        )

        assert "stream_config" in results
        assert "lake_config" in results


class TestWriteNodesFile:
    """Tests for write_nodes_file standalone function."""

    def test_write_nodes_file_basic(self, tmp_path: Path) -> None:
        """Test basic node file writing."""
        output_path = tmp_path / "nodes.dat"
        node_ids = np.array([1, 2, 3], dtype=np.int32)
        x_coords = np.array([0.0, 100.0, 200.0])
        y_coords = np.array([0.0, 100.0, 200.0])

        result = write_nodes_file(output_path, node_ids, x_coords, y_coords)

        assert result.exists()
        content = result.read_text()
        assert "NNODES" in content
        assert "3" in content

    def test_write_nodes_file_with_factor(self, tmp_path: Path) -> None:
        """Test node file with coordinate factor."""
        output_path = tmp_path / "nodes.dat"
        node_ids = np.array([1], dtype=np.int32)
        x_coords = np.array([100.0])
        y_coords = np.array([200.0])

        write_nodes_file(output_path, node_ids, x_coords, y_coords, coord_factor=0.3048)

        content = output_path.read_text()
        assert "0.304800" in content  # coord_factor

    def test_write_nodes_file_creates_parent_dirs(self, tmp_path: Path) -> None:
        """Test that parent directories are created."""
        output_path = tmp_path / "deep" / "path" / "nodes.dat"
        node_ids = np.array([1], dtype=np.int32)
        x_coords = np.array([0.0])
        y_coords = np.array([0.0])

        result = write_nodes_file(output_path, node_ids, x_coords, y_coords)
        assert result.exists()


class TestWriteElementsFile:
    """Tests for write_elements_file standalone function."""

    def test_write_elements_file_basic(self, tmp_path: Path) -> None:
        """Test basic element file writing."""
        output_path = tmp_path / "elements.dat"
        element_ids = np.array([1, 2], dtype=np.int32)
        vertices = np.array([[1, 2, 3, 4], [2, 3, 4, 5]], dtype=np.int32)
        subregions = np.array([1, 1], dtype=np.int32)

        result = write_elements_file(output_path, element_ids, vertices, subregions)

        assert result.exists()
        content = result.read_text()
        assert "NELEM" in content
        assert "NSUBREGION" in content

    def test_write_elements_file_with_names(self, tmp_path: Path) -> None:
        """Test element file with subregion names."""
        output_path = tmp_path / "elements.dat"
        element_ids = np.array([1], dtype=np.int32)
        vertices = np.array([[1, 2, 3, 4]], dtype=np.int32)
        subregions = np.array([1], dtype=np.int32)
        names = {1: "Sacramento Valley"}

        write_elements_file(output_path, element_ids, vertices, subregions, subregion_names=names)

        content = output_path.read_text()
        assert "Sacramento Valley" in content

    def test_write_elements_file_multiple_subregions(self, tmp_path: Path) -> None:
        """Test element file with multiple subregions."""
        output_path = tmp_path / "elements.dat"
        element_ids = np.array([1, 2, 3], dtype=np.int32)
        vertices = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], dtype=np.int32)
        subregions = np.array([1, 2, 1], dtype=np.int32)

        write_elements_file(output_path, element_ids, vertices, subregions)

        content = output_path.read_text()
        assert "2" in content  # NSUBREGION = 2


class TestWriteStratigraphyFile:
    """Tests for write_stratigraphy_file standalone function."""

    def test_write_stratigraphy_file_basic(self, tmp_path: Path) -> None:
        """Test basic stratigraphy file writing."""
        output_path = tmp_path / "strat.dat"
        node_ids = np.array([1, 2], dtype=np.int32)
        ground_surface = np.array([100.0, 110.0])
        layer_tops = np.array([[90.0], [100.0]])
        layer_bottoms = np.array([[70.0], [80.0]])

        result = write_stratigraphy_file(
            output_path, node_ids, ground_surface, layer_tops, layer_bottoms
        )

        assert result.exists()
        content = result.read_text()
        assert "NLAYERS" in content
        assert "1" in content  # 1 layer

    def test_write_stratigraphy_file_multiple_layers(self, tmp_path: Path) -> None:
        """Test stratigraphy file with multiple layers."""
        output_path = tmp_path / "strat.dat"
        node_ids = np.array([1], dtype=np.int32)
        ground_surface = np.array([100.0])
        layer_tops = np.array([[90.0, 70.0]])
        layer_bottoms = np.array([[70.0, 50.0]])

        write_stratigraphy_file(output_path, node_ids, ground_surface, layer_tops, layer_bottoms)

        content = output_path.read_text()
        assert "2" in content  # 2 layers
        assert "AQT_L1" in content or "GSELEV" in content

    def test_write_stratigraphy_file_with_factor(self, tmp_path: Path) -> None:
        """Test stratigraphy file with elevation factor."""
        output_path = tmp_path / "strat.dat"
        node_ids = np.array([1], dtype=np.int32)
        ground_surface = np.array([100.0])
        layer_tops = np.array([[90.0]])
        layer_bottoms = np.array([[70.0]])

        write_stratigraphy_file(
            output_path,
            node_ids,
            ground_surface,
            layer_tops,
            layer_bottoms,
            elev_factor=0.3048,
        )

        content = output_path.read_text()
        assert "0.304800" in content

    def test_write_stratigraphy_file_thickness_calculation(self, tmp_path: Path) -> None:
        """Test that thicknesses are calculated correctly."""
        output_path = tmp_path / "strat.dat"
        node_ids = np.array([1], dtype=np.int32)
        ground_surface = np.array([100.0])
        layer_tops = np.array([[90.0]])  # 10 ft below ground surface
        layer_bottoms = np.array([[70.0]])  # 20 ft aquifer thickness

        write_stratigraphy_file(output_path, node_ids, ground_surface, layer_tops, layer_bottoms)

        # Read and verify data
        content = output_path.read_text()
        lines = content.strip().split("\n")
        data_lines = [line for line in lines if not line.strip().startswith("C") and line.strip()]

        # Find the data line (skip header lines with keywords)
        for line in data_lines:
            parts = line.split()
            if len(parts) >= 4 and parts[0] == "1":  # Node ID 1
                # Columns: ID, GSElev, AQT_L1, AQF_L1
                # AQT_L1 should be 10.0 (100 - 90)
                # AQF_L1 should be 20.0 (90 - 70)
                assert float(parts[1]) == 100.0  # GSElev
                assert float(parts[2]) == 10.0  # Aquitard thickness
                assert float(parts[3]) == 20.0  # Aquifer thickness
                break


class TestPreProcessorWriterEdgeCases:
    """Edge case tests for PreProcessorWriter."""

    def test_empty_subregions(self, tmp_path: Path) -> None:
        """Test handling of empty subregions dict."""
        model = MagicMock()
        model.n_elements = 1

        elem = MagicMock()
        elem.vertices = [1, 2, 3, 4]
        elem.subregion = 1

        model.grid.elements = {1: elem}
        model.grid.subregions = None  # No subregions dict

        config = PreProcessorFileConfig(output_dir=tmp_path)
        writer = PreProcessorWriter(model, config)
        path = writer.write_elements()

        assert path.exists()

    def test_element_without_subregion_attribute(self, tmp_path: Path) -> None:
        """Test element without subregion attribute."""
        model = MagicMock()
        model.n_elements = 1

        elem = MagicMock(spec=[])  # No attributes
        elem.vertices = [1, 2, 3, 4]
        # No subregion attribute

        model.grid.elements = {1: elem}
        model.grid.subregions = {}

        config = PreProcessorFileConfig(output_dir=tmp_path)
        writer = PreProcessorWriter(model, config)

        # Should default to subregion 1
        path = writer.write_elements()
        assert path.exists()

    def test_model_without_name(self, tmp_path: Path) -> None:
        """Test model without name attribute."""
        model = MagicMock(spec=[])  # No attributes
        model.has_streams = False
        model.has_lakes = False

        config = PreProcessorFileConfig(output_dir=tmp_path)
        writer = PreProcessorWriter(model, config)

        path = writer.write_main()
        content = path.read_text()
        # Should use default name
        assert "IWFM Model" in content
