"""
Framework for manipulating bundles for airgapped transfers.
"""
import logging
import sys

from pathlib import Path
from posixpath import sep
from typing import List, Optional

from typer import Exit, echo, prompt

from hoppr import __version__
from hoppr.in_toto import generate_in_toto_layout
from hoppr.models.credentials import Credentials
from hoppr.models.manifest import Manifest
from hoppr.models.transfer import Transfer
from hoppr.processor import HopprProcessor


def bundle(  # pylint: disable=too-many-arguments,too-many-locals
    manifest_file: Path,
    credentials_file: Path,
    transfer_file: Path,
    log_file: Path,
    verbose: bool = False,
    strict_repos: bool = True,
    create_attestations: bool = False,
    functionary_key_path: Optional[Path] = None,
    functionary_key_prompt: bool = False,
    functionary_key_password: Optional[str] = None,
    previous_delivery: Optional[Path] = None,
):
    """
    Run the stages specified in the transfer config
    file on the content specified in the manifest
    """
    echo(
        f"Loading {str(manifest_file).rsplit(str(sep), maxsplit=1)[-1]} and"
        f"{str(transfer_file).rsplit(str(sep), maxsplit=1)[-1]} files..."
    )
    metadata_files = [manifest_file, transfer_file]

    if credentials_file is not None:
        echo(f"Loading {str(credentials_file).rsplit(str(sep), maxsplit=1)[-1]} file...")
        metadata_files.append(credentials_file)

    log_level = logging.DEBUG if verbose else logging.INFO

    if create_attestations and functionary_key_path is None:
        echo("To create attestations both the `--attest` option and a functionary private key need to be provided.")
        raise Exit(code=1)

    if functionary_key_prompt:
        functionary_key_password = prompt(f"Enter password for {str(functionary_key_path)}", hide_input=True)

    processor = HopprProcessor(
        transfer_file=transfer_file,
        manifest_file=manifest_file,
        credentials_file=credentials_file,
        create_attestations=create_attestations,
        functionary_key_path=functionary_key_path,
        functionary_key_password=functionary_key_password,
        log_level=log_level,
        log_file=log_file,
        strict_repos=strict_repos,
        previous_delivery=previous_delivery,
    )

    processor.metadata_files = metadata_files

    result = processor.run()

    if result.is_fail():
        sys.exit(1)


def generate_layout(
    transfer_file: Path,
    project_owner_key_path: Path,
    functionary_key_path: Path,
    project_owner_key_prompt: bool,
    project_owner_key_password: str,
):
    """
    Create in-toto layout based on transfer file.
    """

    if project_owner_key_prompt:
        project_owner_key_password = prompt(f"Enter password for {str(project_owner_key_path)}", hide_input=True)

    transfer = Transfer.load(transfer_file)
    generate_in_toto_layout(transfer, project_owner_key_path, functionary_key_path, project_owner_key_password)


def validate(input_files: List[Path], credentials_file: Path, transfer_file: Path):
    """
    Validate multiple manifest files for schema errors.
    """

    if credentials_file is not None:
        Credentials.load(credentials_file)

    if transfer_file is not None:
        Transfer.load(transfer_file)

    for file in input_files:
        Manifest.load(file)
