import logging
from pathlib import Path
from typing import Optional

import typer
from typing_extensions import Annotated

from yamlex.api.splitter import split_yaml
from yamlex.api.util import (
    adjust_root_logger,
    get_default_extension_dir_path,
    get_default_extension_source_dir_path,
    is_manually_created,
    write_file,
    indent,
)
from yamlex.cli.common_flags import (
    no_file_header_flag,
    force_flag,
    verbose_flag,
    quiet_flag,
    dry_run_flag,
    line_length_option,
    remove_comments_flag,
)


logger = logging.getLogger(__name__)


def split(
    source: Annotated[
        Optional[Path],
        typer.Option(
            "--source",
            "-s",
            help="Path to source extension.yaml file.",
            show_default="extension/extension.yaml or src/extension/extension.yaml",
            dir_okay=False,
            file_okay=True,
            exists=True,
            readable=True,
        ),
    ] = None,
    target: Annotated[
        Optional[Path],
        typer.Option(
            "--target",
            "-t",
            help="Path to directory where split YAML source files will be stored.",
            show_default="source or src/source",
            dir_okay=True,
            file_okay=False,
            exists=True,
            writable=True,
        ),
    ] = None,
    line_length: line_length_option = None,
    dry_run: dry_run_flag = False,
    remove_comments: remove_comments_flag = False,
    no_file_header: no_file_header_flag = False,
    force: force_flag = False,
    verbose: verbose_flag = False,
    quiet: quiet_flag = False,
) -> None:
    """
    Split [i]extension.yaml[/i] file into individual components.

    Performs a "best effort" opinionated splitting. This operation does not
    affect the original extension.yaml file specified by --source. Instead,
    it extracts components from it and places them into individual files
    within the --target folder.

    [b]Splitting multiple times[/b]:

    Theoretically, you only need to split once. However, in practice, you
    can do it over and over again (not very well tested). When performing
    consequent splittings, the command overwrites any previously generated
    split files, if they have the 'Generated by yamlex' header within them.
    If the target split part does not have that header, it is considered
    to be manually created and is not overwritten. You can still force
    the overwrite using the --force flag.

    [b]Remove 'Generated with yamlex' header from split files[/b]:

    When splitting, you can choose to not add the 'Generated by yamlex'
    header to the generated files by using the --no-file-header flag.
    """
    adjust_root_logger(verbose, quiet)

    source = source or get_default_extension_dir_path() / "extension.yaml"
    logger.debug(f"Source file: {source}")

    target = target or get_default_extension_source_dir_path()
    logger.debug(f"Target directory: {target}")

    split_parts = split_yaml(
        source,
        target,
        remove_comments=remove_comments,
    )

    parts_to_skip: list[Path] = []
    for path in split_parts.keys():
        if is_manually_created(path) and not force:
            part = split_parts.pop(path)
            parts_to_skip.append(part)

    if parts_to_skip:
        logger.info((
            "The following split parts will not be written, because "
            "an unmarked file with the same name already exists in the "
            "target path. Unmarked files do not have the "
            "'Generated with yamlex' header, and thus are considered to be "
            "manually created or edited. Use --force to overwrite this "
            "behavior."
        ))
        for p in parts_to_skip:
            logger.info(f"{indent(1)}Skip: {p}")

    if not split_parts:
        logger.info("No part files to be written.")
    else:
        logger.info("The following part files will be written:")
        for path, part in split_parts.items():
            write_file(
                path,
                part,
                add_file_header=not no_file_header,
                line_length=line_length,
                dry_run=dry_run,
                print_to_stdout=False,
            )
            logger.info(f"{indent(1)}Added: {path}")
