"""
:mod:`etlplus.file.log` module.

Helpers for reading/writing generic log (LOG) files.

Notes
-----
- A LOG file is a plain text file that contains log messages generated by
    applications or systems.
- Common cases:
    - Each line in the file represents a single log entry.
    - Log entries may include timestamps, log levels, and messages.
    - Formats may vary widely depending on the application generating the logs.
- Rule of thumb:
    - If the file is a generic log file, use this module for reading and
        writing.
"""

from __future__ import annotations

import json
from pathlib import Path

from ..types import JSONData
from ..types import JSONDict
from ..types import JSONList
from ..types import StrPath
from ._io import call_deprecated_module_read
from ._io import call_deprecated_module_write
from ._io import normalize_records
from ._io import write_text
from .base import LogEventFileHandlerABC
from .base import ReadOptions
from .base import WriteOptions
from .enums import FileFormat

# SECTION: EXPORTS ========================================================== #


__all__ = [
    # Classes
    'LogFile',
    # Functions
    'read',
    'write',
]


# SECTION: CLASSES ========================================================== #


class LogFile(LogEventFileHandlerABC):
    """
    Handler implementation for LOG files.
    """

    # -- Class Attributes -- #

    format = FileFormat.LOG

    # -- Instance Methods -- #

    def parse_line(
        self,
        line: str,
    ) -> JSONDict:
        """
        Parse one LOG line into one event object.

        Parameters
        ----------
        line : str
            One log line.

        Returns
        -------
        JSONDict
            Parsed event dictionary.
        """
        try:
            parsed = json.loads(line)
        except json.JSONDecodeError:
            return {'message': line}
        if isinstance(parsed, dict):
            return parsed
        return {'message': line}

    def read(
        self,
        path: Path,
        *,
        options: ReadOptions | None = None,
    ) -> JSONList:
        """
        Read and return LOG events from *path*.

        Parameters
        ----------
        path : Path
            Path to the LOG file on disk.
        options : ReadOptions | None, optional
            Optional read parameters.

        Returns
        -------
        JSONList
            Parsed event dictionaries.
        """
        encoding = self.encoding_from_read_options(options)
        rows: JSONList = []
        with path.open('r', encoding=encoding) as handle:
            for raw_line in handle:
                line = raw_line.rstrip('\n')
                if not line.strip():
                    continue
                rows.append(self.parse_line(line))
        return rows

    def serialize_event(
        self,
        event: JSONDict,
    ) -> str:
        """
        Serialize one event object into one LOG line.

        Parameters
        ----------
        event : JSONDict
            Event dictionary to serialize.

        Returns
        -------
        str
            Serialized log line.
        """
        return json.dumps(event, ensure_ascii=False)

    def write(
        self,
        path: Path,
        data: JSONData,
        *,
        options: WriteOptions | None = None,
    ) -> int:
        """
        Write LOG events to *path* and return event count.

        Parameters
        ----------
        path : Path
            Path to the LOG file on disk.
        data : JSONData
            Event payload as one object or an array of objects.
        options : WriteOptions | None, optional
            Optional write parameters.

        Returns
        -------
        int
            Number of events written.
        """
        rows = normalize_records(data, self.format_name)
        if not rows:
            return 0
        payload = '\n'.join(self.serialize_event(event) for event in rows)
        write_text(
            path,
            payload,
            encoding=self.encoding_from_write_options(options),
            trailing_newline=True,
        )
        return len(rows)


# SECTION: INTERNAL CONSTANTS =============================================== #


_LOG_HANDLER = LogFile()


# SECTION: FUNCTIONS ======================================================== #


def read(
    path: StrPath,
) -> JSONList:
    """
    Deprecated wrapper. Use ``LogFile().read(...)`` instead.

    Parameters
    ----------
    path : StrPath
        Path to the LOG file on disk.

    Returns
    -------
    JSONList
        The list of dictionaries read from the LOG file.
    """
    return call_deprecated_module_read(
        path,
        __name__,
        _LOG_HANDLER.read,
    )


def write(
    path: StrPath,
    data: JSONData,
) -> int:
    """
    Deprecated wrapper. Use ``LogFile().write(...)`` instead.

    Parameters
    ----------
    path : StrPath
        Path to the LOG file on disk.
    data : JSONData
        Data to write as LOG. Should be a list of dictionaries or a
        single dictionary.

    Returns
    -------
    int
        The number of rows written to the LOG file.
    """
    return call_deprecated_module_write(
        path,
        data,
        __name__,
        _LOG_HANDLER.write,
    )
