# Copyright (C) 2007-2024 Andrea Francia Trivolzio(PV) Italy
import os
from typing import List
from typing import Tuple

from trashcli.put.fs.fs import Fs

from trashcli.lib.environ import Environ
from trashcli.lib.exit_codes import EX_IOERR
from trashcli.lib.exit_codes import EX_OK
from trashcli.put.core.candidate import Candidate
from trashcli.put.core.failure_reason import FailureReason
from trashcli.put.core.failure_reason import LogContext
from trashcli.put.core.logs import Level
from trashcli.put.core.logs import LogEntry
from trashcli.put.core.logs import LogTag
from trashcli.put.core.logs import debug_str
from trashcli.put.core.logs import info_str
from trashcli.put.core.logs import log_str
from trashcli.put.core.trash_all_result import TrashAllResult
from trashcli.put.core.trashee import Trashee
from trashcli.put.describer import Describer
from trashcli.put.reporting.stats_reader import gentle_stat_read


class TrashPutReporter:
    def __init__(self,
                 fs,  # type: Fs
                 ):
        self.describer = Describer(fs)

    def _describe(self, path):
        return self.describer.describe(path)

    def unable_to_trash_dot_entries(self, file
                                    ):  # type: (...) -> LogEntry
        return log_str(Level.WARNING, LogTag.trash_failed,
                       ["cannot trash %s '%s'" % (self._describe(file), file)])

    def unable_to_trash_file_non_existent(self,
                                          path,  # type: str
                                          ):  # type: (...) -> LogEntry
        return log_str(Level.WARNING, LogTag.trash_failed,
                       ["cannot trash %s '%s'" % (self._describe(path), path)])

    def unable_to_trash_file(
            self,
            trashee,  # type: Trashee
            failures,  # type: List[Tuple[Candidate, FailureReason]]
            environ,  # type: Environ
    ):  # (...) -> LogEntry
        path = trashee.path
        volume = trashee.volume
        messages = []
        messages.append("cannot trash %s '%s' (from volume '%s')" % (
            self._describe(path), path, volume))
        for candidate, reason in failures:
            context = LogContext(path, candidate, environ)
            message = " `- failed to trash %s in %s, because %s" % (
                path,
                candidate.norm_path(),
                reason.log_entries(context))
            messages.append(message)

        return log_str(Level.WARNING, LogTag.trash_failed, messages)

    @staticmethod
    def file_has_been_trashed_in_as(trashed_file,
                                    trash_dir,  # type: Candidate
                                    environ):  # type: (...) -> LogEntry
        return info_str("'%s' trashed in %s" % (trashed_file,
                                                trash_dir.shrink_user(environ)))

    @classmethod
    def log_data_for_debugging(cls, error):
        try:
            filename = error.filename
        except AttributeError:
            pass
        else:
            if filename is not None:
                for path in [filename, os.path.dirname(filename)]:
                    info = gentle_stat_read(path)
                    yield "stats for %s: %s" % (path, info)

    @staticmethod
    def trash_dir_with_volume(candidate,  # type: Candidate
                              ):  # type: (...) -> LogEntry
        return debug_str("trying trash dir: %s from volume: %s" % (
            candidate.norm_path(), candidate.volume))

    @staticmethod
    def exit_code(result,  # type: TrashAllResult
                  ):  # type: (...) -> int
        if not result.any_failure():
            return EX_OK
        else:
            return EX_IOERR
