"""
Context object used by sync command
"""
import logging
from dataclasses import dataclass
from pathlib import Path
from typing import Optional, cast, Dict

import tomlkit
from tomlkit.toml_document import TOMLDocument
from tomlkit.items import Item

from samcli.lib.build.build_graph import DEFAULT_DEPENDENCIES_DIR
from samcli.lib.utils.osutils import rmtree_if_exists

LOG = logging.getLogger(__name__)


DEFAULT_SYNC_STATE_FILE_NAME = "sync.toml"

SYNC_STATE = "sync_state"
DEPENDENCY_LAYER = "dependency_layer"


@dataclass
class SyncState:
    dependency_layer: bool


def _sync_state_to_toml_document(sync_state: SyncState) -> TOMLDocument:
    sync_state_toml_table = tomlkit.table()
    sync_state_toml_table[DEPENDENCY_LAYER] = sync_state.dependency_layer

    toml_document = tomlkit.document()
    toml_document.add((tomlkit.comment("This file is auto generated by SAM CLI sync command")))
    toml_document.add(SYNC_STATE, cast(Item, sync_state_toml_table))

    return toml_document


def _toml_document_to_sync_state(toml_document: Dict) -> Optional[SyncState]:
    if not toml_document:
        return None

    sync_state_toml_table = toml_document.get(SYNC_STATE)
    if not sync_state_toml_table:
        return None

    return SyncState(sync_state_toml_table.get(DEPENDENCY_LAYER))


class SyncContext:

    _current_state: SyncState
    _previous_state: Optional[SyncState]
    _build_dir: Path
    _cache_dir: Path
    _file_path: Path

    def __init__(self, dependency_layer: bool, build_dir: str, cache_dir: str):
        self._current_state = SyncState(dependency_layer)
        self._previous_state = None
        self._build_dir = Path(build_dir)
        self._cache_dir = Path(cache_dir)
        self._file_path = Path(build_dir).parent.joinpath(DEFAULT_SYNC_STATE_FILE_NAME)

    def __enter__(self) -> "SyncContext":
        self._read()
        LOG.debug(
            "Entering sync context, previous state: %s, current state: %s", self._previous_state, self._current_state
        )

        # if adl parameter is changed between sam sync runs, cleanup build, cache and dependencies folders
        if self._previous_state and self._previous_state.dependency_layer != self._current_state.dependency_layer:
            self._cleanup_build_folders()

        return self

    def __exit__(self, *args):
        self._write()

    def _write(self) -> None:
        with open(self._file_path, "w+") as file:
            file.write(tomlkit.dumps(_sync_state_to_toml_document(self._current_state)))

    def _read(self) -> None:
        try:
            with open(self._file_path) as file:
                toml_document = cast(Dict, tomlkit.loads(file.read()))
            self._previous_state = _toml_document_to_sync_state(toml_document)
        except OSError:
            LOG.debug("Missing previous sync state, will create a new file at the end of this execution")

    def _cleanup_build_folders(self):
        """
        Cleans up build, cache and dependencies folders for clean start of the next session
        """
        LOG.debug("Cleaning up build directory %s", self._build_dir)
        rmtree_if_exists(self._build_dir)

        LOG.debug("Cleaning up cache directory %s", self._cache_dir)
        rmtree_if_exists(self._cache_dir)

        dependencies_dir = Path(DEFAULT_DEPENDENCIES_DIR)
        LOG.debug("Cleaning up dependencies directory: %s", dependencies_dir)
        rmtree_if_exists(dependencies_dir)
