from __future__ import annotations

import os
from pathlib import Path
from subprocess import Popen

from bmde.core import logging
from bmde.core.exec import ExecOptions

from ...config.loader import load_settings
from ...core.logging import configure_logging_from_settings
from ...core.spec_opts import SpecExecOpts
from ...core.types import BackendOptions
from .service import GitService
from .settings import GitSettings
from .spec import GitSpec, GitSpecOpts

log = logging.get_logger(__name__)


def create_git_spec(
    d: Path | None,
    arguments: list[str] | None = None,
    backend: BackendOptions | None = None,
    interactive: bool = True,
    dry_run: bool = True,
    entrypoint: Path | None = None,
    ssh_username: str | None = None,
    ssh_password: str | None = None,
    ssh_host: str | None = None,
    git_name: str | None = None,
    git_email: str | None = None,
    vpn_username: str | None = None,
    vpn_password: str | None = None,
    vpn_host: str | None = None,
    vpn_port: int | None = None,
    vpn_realm: str | None = None,
    vpn_cert: str | None = None,
    vpn_test_dns: str | None = None,
    vpn_test_ip: str | None = None,
    settings: GitSettings | None = None,
) -> GitSpec:
    if d is None:
        d = Path(os.getcwd())

    if settings is None:
        settings = GitSettings()

    return GitSpec(
        GitSpecOpts=GitSpecOpts(
            d=d,
            ssh_username=(
                ssh_username if ssh_username is not None else settings.ssh.username
            ),
            ssh_password=(
                ssh_password if ssh_password is not None else settings.ssh.password
            ),
            ssh_host=ssh_host if ssh_host is not None else settings.ssh.host,
            git_name=git_name if git_name is not None else settings.git.name,
            git_email=git_email if git_email is not None else settings.git.email,
            vpn_username=(
                vpn_username if vpn_username is not None else settings.vpn.username
            ),
            vpn_password=(
                vpn_password if vpn_password is not None else settings.vpn.password
            ),
            vpn_host=vpn_host if vpn_host is not None else settings.vpn.host,
            vpn_port=vpn_port if vpn_port is not None else settings.vpn.port,
            vpn_realm=vpn_realm if vpn_realm is not None else settings.vpn.realm,
            vpn_cert=vpn_cert if vpn_cert is not None else settings.vpn.cert,
            vpn_test_dns=(
                vpn_test_dns if vpn_test_dns is not None else settings.vpn.test_dns
            ),
            vpn_test_ip=(
                vpn_test_ip if vpn_test_ip is not None else settings.vpn.test_ip
            ),
        ),
        SpecExecOpts=SpecExecOpts(
            backend=(
                backend
                if backend is not None
                else (
                    settings.execution_settings.backend
                    if settings.execution_settings.backend is not None
                    else BackendOptions.DOCKER
                )
            ),
            entrypoint=(
                entrypoint
                if entrypoint is not None
                else settings.execution_settings.entrypoint
            ),
            arguments=arguments,
            dry_run=(
                dry_run if dry_run is not None else settings.execution_settings.dry_run
            ),
            background=(
                settings.execution_settings.background
                if settings.execution_settings.background is not None
                else False
            ),
            interactive=(
                interactive
                if interactive is not None
                else settings.execution_settings.interactive
            ),
        ),
    )


def execute_git(spec: GitSpec) -> int | Popen[bytes]:
    return GitService().run(
        spec.GitSpecOpts,
        ExecOptions(
            dry_run=spec.SpecExecOpts.dry_run,
            background=spec.SpecExecOpts.background,
            interactive=spec.SpecExecOpts.interactive,
            entrypoint=spec.SpecExecOpts.entrypoint,
            arguments=spec.SpecExecOpts.arguments,
            backend=spec.SpecExecOpts.backend,
        ),
    )


def git_command(
    d: Path | None,
    arguments: list[str] | None = None,
    backend: BackendOptions | None = None,
    dry_run: bool = False,
    interactive: bool = True,
    entrypoint: Path | None = None,
    ssh_username: str | None = None,
    ssh_password: str | None = None,
    ssh_host: str | None = None,
    git_name: str | None = None,
    git_email: str | None = None,
    vpn_username: str | None = None,
    vpn_password: str | None = None,
    vpn_host: str | None = None,
    vpn_port: int | None = None,
    vpn_realm: str | None = None,
    vpn_cert: str | None = None,
    vpn_test_dns: str | None = None,
    vpn_test_ip: str | None = None,
    settings: GitSettings | None = None,
) -> int | Popen[bytes]:

    if settings is None:
        full_settings = load_settings()
        configure_logging_from_settings(settings=full_settings)
        settings = full_settings.git

    spec = create_git_spec(
        d=d,
        arguments=arguments,
        backend=backend,
        dry_run=dry_run,
        interactive=interactive,
        entrypoint=entrypoint,
        ssh_username=ssh_username,
        ssh_password=ssh_password,
        ssh_host=ssh_host,
        git_name=git_name,
        git_email=git_email,
        vpn_username=vpn_username,
        vpn_password=vpn_password,
        vpn_host=vpn_host,
        vpn_port=vpn_port,
        vpn_realm=vpn_realm,
        vpn_cert=vpn_cert,
        vpn_test_dns=vpn_test_dns,
        vpn_test_ip=vpn_test_ip,
        settings=settings,
    )

    return execute_git(spec)
