"""
文件解析工具模块

提供多种格式的文件解析功能，支持：
- 纯文本文件（TEXT）
- GZIP压缩文件
- ZIP压缩文件
- BZ2压缩文件
- TGZ压缩包（tar.gz）

使用迭代器模式逐行读取文件，将每行解析为字典格式。

Example:
    >>> field_list = ["name", "age", "city"]
    >>> parser = FileParser("data.txt", field_list, ",")
    >>> for row in parser:
    ...     print(row["name"], row["age"])
"""
import os
import bz2
import gzip
import queue
import tarfile
import zipfile
import logging
from typing import List, Dict, Optional, Any, Iterator, Union, IO

logger = logging.getLogger(__name__)


class FileType:
    """
    文件类型常量类

    定义支持的文件类型标识符。

    Attributes:
        FILE_TYPE_TEXT: 纯文本文件
        FILE_TYPE_GZIP: GZIP压缩文件（.gz）
        FILE_TYPE_ZIP: ZIP压缩文件（.zip）
        FILE_TYPE_BZ2: BZ2压缩文件（.bz2）
        FILE_TYPE_TGZ: TGZ压缩包（.tar.gz）
    """
    FILE_TYPE_TEXT: int = 1
    FILE_TYPE_GZIP: int = 2
    FILE_TYPE_ZIP: int = 3
    FILE_TYPE_BZ2: int = 4
    FILE_TYPE_TGZ: int = 5


class FileParser:
    """
    文件解析器类

    使用迭代器模式逐行读取文件，并将每行按分隔符解析为字典。
    支持多种文件格式：纯文本、GZIP、ZIP、BZ2、TGZ。

    Attributes:
        file_name: 文件路径
        filed_list: 字段名列表
        filed_sep: 字段分隔符
        file_type: 文件类型
        file_handle: 文件句柄
        line: 当前读取的行
        tar_file: tar文件对象（仅TGZ格式使用）
        tar_file_members: tar成员队列（仅TGZ格式使用）

    Example:
        >>> fields = ["id", "name", "value"]
        >>> parser = FileParser("data.csv", fields, ",")
        >>> for row in parser:
        ...     print(row)
        >>> parser.close()

    Note:
        使用时需要捕获IOError异常处理文件读取错误。
    """

    def __init__(
        self,
        file_name: str,
        field_list: List[str],
        field_sep: str,
        file_type: int = FileType.FILE_TYPE_TEXT
    ):
        """
        初始化文件解析器

        Args:
            file_name: 文件路径
            field_list: 字段名列表，用于将每行数据映射为字典
            field_sep: 字段分隔符
            file_type: 文件类型，默认为纯文本
        """
        logger.info(f"FileParser: {file_name}")
        self.file_name: str = file_name
        self.filed_list: List[str] = field_list
        self.filed_sep: str = field_sep
        self.file_handle: Optional[IO[Any]] = None
        self.file_type: int = file_type
        self.line: str = ""
        self.tar_file: Optional[tarfile.TarFile] = None
        self.tar_file_members: queue.Queue[tarfile.TarInfo] = queue.Queue()

    def __iter__(self) -> "FileParser":
        """
        初始化迭代器

        根据文件类型打开相应的文件句柄。

        Returns:
            FileParser实例自身

        Raises:
            IOError: 文件打开失败时抛出
        """
        if self.file_type == FileType.FILE_TYPE_GZIP:
            self.file_handle = gzip.open(self.file_name, "rt", encoding="utf-8")
        elif self.file_type == FileType.FILE_TYPE_ZIP:
            self.file_handle = zipfile.ZipFile(self.file_name, "r")
        elif self.file_type == FileType.FILE_TYPE_BZ2:
            self.file_handle = bz2.open(self.file_name, "rt", encoding="utf-8")
        elif self.file_type == FileType.FILE_TYPE_TGZ:
            self.tar_file = tarfile.open(self.file_name, "r:gz")
            for member in self.tar_file.getmembers():
                if member.isfile():
                    self.tar_file_members.put(member)
        else:
            self.file_handle = open(self.file_name, "r", encoding="utf-8")

        return self

    def __next__(self) -> Dict[str, str]:
        """
        获取下一行数据

        读取文件的下一行，按分隔符拆分后映射为字典。

        Returns:
            字段名到字段值的字典

        Raises:
            StopIteration: 文件读取完毕时抛出
            IOError: 文件读取错误时抛出
        """
        try:
            # TGZ格式特殊处理：需要逐个处理tar包中的文件
            if self.file_type == FileType.FILE_TYPE_TGZ and self.file_handle is None:
                if self.tar_file_members.empty():
                    raise StopIteration
                self.file_handle = self.tar_file.extractfile(self.tar_file_members.get())
                if self.file_handle is None:
                    raise StopIteration

            # 读取一行
            line_bytes = self.file_handle.readline()

            # 处理bytes类型（TGZ格式返回bytes）
            if isinstance(line_bytes, bytes):
                self.line = line_bytes.decode("utf-8")
            else:
                self.line = line_bytes

            # 检查是否到达文件末尾
            if self.line == "":
                self.file_handle.close()
                self.file_handle = None
                # TGZ格式：尝试打开下一个文件
                if self.file_type == FileType.FILE_TYPE_TGZ:
                    return self.__next__()
                raise StopIteration

            # 去除行尾换行符并分割
            if self.line.endswith(os.linesep):
                line_array = self.line[:-len(os.linesep)].split(self.filed_sep)
            elif self.line.endswith("\n"):
                line_array = self.line[:-1].split(self.filed_sep)
            else:
                line_array = self.line.split(self.filed_sep)

            # 将字段列表与值列表组合为字典
            line_dict = dict(zip(self.filed_list, line_array))

        except IOError as error:
            logger.error(f"FileParser read {self.file_name} failed: {error}")
            raise error

        return line_dict

    def close(self) -> None:
        """
        关闭文件句柄

        释放文件资源，包括普通文件句柄和tar文件句柄。
        """
        if self.file_handle:
            self.file_handle.close()
            self.file_handle = None
        if self.tar_file:
            self.tar_file.close()
            self.tar_file = None

    def __enter__(self) -> "FileParser":
        """
        上下文管理器入口

        Returns:
            FileParser实例自身
        """
        return self.__iter__()

    def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
        """
        上下文管理器退出

        Args:
            exc_type: 异常类型
            exc_val: 异常值
            exc_tb: 异常追溯
        """
        self.close()


if __name__ == "__main__":
    pass
