# -*- coding: utf-8 -*-
from __future__ import annotations

import base64
import datetime

from invoke import Context, task

from hotpocket_workspace_tools import get_workspace_mode, WorkspaceMode
from hotpocket_workspace_tools.tasks import (
    bump_version as tools_bump_version_task,
)


class DockerBuildContext:
    def __init__(self,
                 /,
                 target='deployment',
                 version=None,
                 build='01',
                 machine=None,
                 ):
        self._target = target
        self._version = version
        self._build = build

        self._image_arch = None
        self._node_arch = None

    def __enter__(self, *args, **kwargs):
        return self

    def __exit__(self, *args, **kwargs):
        pass

    @property
    def target(self) -> str:
        return self._target

    @property
    def version(self) -> str:
        return self._version or datetime.date.today().strftime('%Y%m%d')

    @property
    def build(self) -> str:
        return self._build.zfill(2)

    @property
    def image_arch(self) -> str:
        return self._image_arch

    @property
    def node_arch(self) -> str:
        return self._node_arch

    @property
    def tag(self) -> str:
        return '{target}-{version}-{build}'.format(
            target=self.target,
            version=self.version,
            build=self.build,
        )


WORKSPACE_MODE = get_workspace_mode()

ALL_SERVICES = ['apple', 'backend', 'extension', 'packages']
VERSIONED_SERVICES = ['apple', 'backend', 'extension']


def _run_in_service(ctx: Context, service, command, **kwargs):
    match WORKSPACE_MODE:
        case WorkspaceMode.DOCKER:
            return ctx.run(
                f'docker compose run --rm -it {service}-management {command}',
            )

        case WorkspaceMode.METAL:
            with ctx.cd(f'services/{service}'):
                ctx.run(f'direnv exec . {command}')


def _get_version(ctx: Context, service):
    with ctx.cd(f'services/{service}'):
        run_result = ctx.run('poetry version -s', hide='out')

        return run_result.stdout.strip()


def _get_head_sha(ctx: Context):
    run_result = ctx.run('git rev-parse HEAD', hide='out')
    return run_result.stdout.strip()


@task
def clean(ctx: Context, service):
    _run_in_service(ctx, service, 'inv clean')


@task
def test(ctx: Context, service):
    _run_in_service(ctx, service, 'inv test')


@task
def lint(ctx: Context, service):
    _run_in_service(ctx, service, 'inv lint')


@task
def typecheck(ctx: Context, service):
    _run_in_service(ctx, service, 'inv typecheck')


@task
def shell(ctx: Context, service):
    assert WORKSPACE_MODE == WorkspaceMode.DOCKER, (
        'Just `cd services/{service}` ;)'
    )
    _run_in_service(ctx, service, '/bin/bash')


@task
def django_shell(ctx: Context, service):
    _run_in_service(ctx, service, 'inv django-shell')


@task
def png_to_data_url(ctx: Context, png_path):
    with open(png_path, 'rb') as png_f:
        data = png_f.read()

    encoded_data = base64.b64encode(data)
    print(f'data:image/png;base64,{encoded_data.decode("utf-8")}')


@task
def build(ctx: Context,
          service,
          context=None,
          builder=None,
          push=False,
          target='deployment',
          version=None,
          build='01',
          image_tag=None,
          machine=None,
          platform=None,
          registry='docker-hosted.nexus.bthlabs.pl',
          ):
    image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target)

    short_sha = _get_head_sha(ctx)[:8]
    image_tag = image_tag.format(
        short_sha=short_sha,
    )

    with DockerBuildContext(target, version, build, machine) as docker_build_ctx:  # noqa: E501
        commandline = [
            'docker',
            (
                f'--context {context}'
                if context is not None
                else ''
            ),
            'buildx build',
            (
                f'--builder {builder}'
                if builder is not None
                else ''
            ),
            (
                '--push'
                if push is True
                else ''
            ),
            (
                f'--platform {platform}'
                if platform is not None
                else ''
            ),
            f'-t {registry}/hotpocket/{service}:{docker_build_ctx.tag}',  # noqa: E501
            f'-f services/{service}/Dockerfile',
            f'--build-arg IMAGE_ID={image_tag}',
            f'--build-arg IMAGE_VERSION={version}',
            f'--build-arg IMAGE_REVISION={short_sha}',
            f'--target {docker_build_ctx.target}',
            'services/',
        ]

        ctx.run(' '.join(commandline))


@task
def publish(ctx: Context,
            service,
            context=None,
            target='deployment',
            version=None,
            build='01',
            machine=None,
            ):
    with DockerBuildContext(target, version, build, machine) as docker_build_ctx:  # noqa: E501
        commandline = [
            'docker',
            (
                f'--context {context}'
                if context is not None
                else ''
            ),
            'push',
            f'docker-hosted.nexus.bthlabs.pl/hotpocket/{service}:{docker_build_ctx.tag}',  # noqa: E501
        ]

        ctx.run(' '.join(commandline))


@task
def ci(ctx: Context, service):
    _run_in_service(ctx, service, 'inv ci')


@task
def setup(ctx: Context, service=None):
    services_to_setup = []

    services_to_setup = [*ALL_SERVICES]
    if service is not None:
        services_to_setup = [service]

    for service_to_setup in services_to_setup:
        _run_in_service(ctx, service_to_setup, 'inv setup')


@task
def install(ctx: Context, service=None):
    services_to_setup = []

    services_to_setup = [*ALL_SERVICES]
    if service is not None:
        services_to_setup = [service]

    for service_to_setup in services_to_setup:
        _run_in_service(ctx, service_to_setup, 'poetry install')


@task
def lock(ctx: Context, service):
    _run_in_service(ctx, service, 'poetry lock')


@task
def start_cloud(ctx: Context):
    ctx.run('docker compose -f docker-compose-cloud.yaml up')


@task
def start_web(ctx: Context, service):
    _run_in_service(ctx, service, 'inv start-web')


@task
def start_celery_worker(ctx: Context, service):
    _run_in_service(ctx, service, 'inv start-celery-worker')


@task
def start_celery_beat(ctx: Context, service):
    _run_in_service(ctx, service, 'inv start-celery-beat')


@task
def start_app(ctx: Context, service, app):
    _run_in_service(ctx, service, f'inv start-{app}')


@task
def bump_version(ctx: Context,
                 next_version: str,
                 build: str | None = None,
                 service: str | None = None,
                 ):
    assert build is not None, '`--build` is required here'

    services_to_bump = [*VERSIONED_SERVICES]
    if service is not None:
        services_to_bump = [service]

    for service_to_setup in services_to_bump:
        _run_in_service(
            ctx,
            service_to_setup,
            f'inv bump-version {next_version} --build {build}',
        )

    if service is None:
        tools_bump_version_task(ctx, next_version, build=build)
