# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/info.ipynb (unless otherwise specified).

__all__ = ['insp2acao', 'issue_type', 'utf2ascii', 'detalhar_issue', 'download_attachments', 'extract_attachments']

# Cell
import re
from unidecode import unidecode
from datetime import datetime, timedelta
import contextlib
from pathlib import Path
from typing import Union

from rich import print
from redminelib import Redmine
from redminelib.resources import Issue
from redminelib.exceptions import ResourceAttrError

from fastcore.foundation import L
from fastcore.xtras import is_listy, listify
from fastcore.script import Param, call_parse, bool_arg


from .constants import ACAO_DESCRIPTION, KWARGS, IDS, FIELDS, JSON_FIELDS
from .validation import valida_fiscaliza, issue2users
from .format import view_string

# Cell
def insp2acao(insp: str, fiscaliza: Redmine) -> dict:
    """Recebe o objeto `fiscaliza` e a string referente à inspeção `insp` e retorna um dicionário resumo da Ação atrelada à inspeção

    Args:
        redmineObj (Redmine): Objeto Redmine autenticado
        insp (str): string com o número da inspeção

    Returns:
        dict: Dicionário com o id, nome e descrição da Ação associada à inspeção

    """
    fiscaliza = valida_fiscaliza(fiscaliza=fiscaliza)
    issue = fiscaliza.issue.get(insp, include=["relations", "attachments"])

    if "INSP" not in str(issue.subject):
        return {}
    if relations := getattr(issue, "relations", []):
        if relations := getattr(relations, "values", []):
            relations = relations()
    for relation in relations:
        if issue_to_id := relation.get("issue_to_id", None):
            if issue_to_id := fiscaliza.issue.get(issue_to_id):
                if "ACAO" in str(issue_to_id) or (
                    (tracker := getattr(issue_to_id, "tracker", None))
                    and (getattr(tracker, "id", None) == 2)
                ):
                    if (
                        description := getattr(issue_to_id, "custom_fields", None)
                    ) is None:
                        description = ""

                    elif description := description.get(ACAO_DESCRIPTION, None):
                        description = getattr(description, "value", "")
                    else:
                        description = ""
                    return {
                        "id_ACAO": getattr(issue_to_id, "id", ""),
                        "nome_ACAO": str(issue_to_id),
                        "descricao_ACAO": description,
                    }
    return {"id_ACAO": "", "nome_ACAO": "", "descricao_ACAO": ""}

# Cell
def issue_type(insp, fiscaliza):
    """Checa se a Issue de nº `insp` do Redmine é de um dos tipos válidos: `Inspeção | Ação`"""
    if (tipo := fiscaliza.issue.get(insp).tracker["id"]) == 1:
        return "Inspeção"
    elif tipo == 2:
        return "Ação"
    return "Desconhecido"

# Cell
def utf2ascii(s):
    """Recebe uma string e retorna a mesma em formato ASCII"""
    s = re.sub("[!\"#$%&'()*+\,\-\.\/:;<=>\?@[\\]\^`_\{\|\}~]", "", s)
    return unidecode(s.replace(" ", "_"))


def detalhar_issue(
    issue: str,
    login: str = None,
    senha: str = None,
    api: str = None,
    fiscaliza: Redmine = None,
    teste: bool = True,
) -> dict:
    """Recebe número da inspeção `inspecao`, o login e senha ou opcionalmente objeto Redmine logado `fiscaliza`
    inspecao: str - Número da Inspeção a ser relatada
    login: str - Login Anatel do Usuário
    senha: str - Senha Utilizada nos Sistemas Interativos da
    fiscaliza: Redmine - Objeto Redmine logado, opcional ao login e senha
    teste: bool - Caso verdadeiro o Fiscaliza de Teste ( Homologação ) é utilizado

    Returns:
        dict: Retorna um dicionário com a Situação Atual e campos preenchidos da Inspeção

    """

    fiscaliza = valida_fiscaliza(login, senha, api, fiscaliza, teste)

    issue_data = {}
    i = fiscaliza.issue.get(issue, include=["relations", "attachments"])

    if (attachments := getattr(i, "attachments")) is not None:
        issue_data["Anexos"] = {d["filename"]: d["content_url"] for d in attachments}

    issue_data.update({k: getattr(i, k, "") for k in KWARGS})

    id2field = dict(zip(IDS, FIELDS))

    if custom_fields := listify(getattr(i, "custom_fields", None)):
        for field in custom_fields:
            try:
                issue_data[id2field.get(field.id, utf2ascii(field.name))] = getattr(
                    field, "value", ""
                )
            except ResourceAttrError as e:
                raise ValueError(
                    f"O atributo 'value' não existe na Issue mencionada: key {field.id}, name: {field.name}"
                ) from e

    issue_data.update(insp2acao(issue, fiscaliza))
    id2users, users2id = issue2users(issue, fiscaliza)

    if (value := issue_data.get("Fiscal_Responsavel", None)) is not None:
        with contextlib.suppress(ValueError):
            issue_data["Fiscal_Responsavel"] = id2users.get(int(value), value)

    if (value := issue_data.get("Fiscais", None)) is not None:
        with contextlib.suppress(ValueError):
            issue_data["Fiscais"] = [
                id2users.get(int(v), v) for v in issue_data["Fiscais"]
            ]

    users = list(users2id.keys())
    issue_data["Users"] = users

    for f in JSON_FIELDS:
        if (field := issue_data.get(f)) is None:
            issue_data[f] = ""
            continue
        if is_listy(field):
            issue_data[f] = [view_string(s) for s in field]
        else:
            issue_data[f] = view_string(field)

    if journal := list(i.journals):
        journal = dict(journal[-1])
        key = "user"
    else:
        journal = dict(i)
        key = "author"

    user = journal[key]["name"]
    date = datetime.strptime(journal["created_on"], "%Y-%m-%dT%H:%M:%SZ") - timedelta(
        hours=3
    )

    issue_data[
        "Atualizado"
    ] = f"Atualizado por {user} em {datetime.strftime(date, '%d/%m/%Y')} às {date.time()}"

    return issue_data


def _download_attachment(
    attach: Issue,
    savepath: Path,
) -> None:
    """Recebe número da inspeção `inspecao`, o login e senha ou opcionalmente objeto Redmine logado `fiscaliza`
    issue_obj: Issue - Objeto na qual o anexo está contido
    fiscaliza: Redmine - Objeto Redmine logado, opcional ao login e senha
    savepath: str - Caminho para salvar o anexo

    Returns:
        None: Somente salva os arquivos desejados.
    """

    url = getattr(attach, "content_url").replace("http://", "https://")
    setattr(attach, "content_url", url)
    attach.download(
        savepath=savepath,
        filename=f"{attach.id}_{attach.filename}",
    )


@call_parse  # Workaround the bug in recursion call in extract_attachments when using as a console script
def _download_attachments(
    issue_obj: Param("Número da Issue ou Objeto Issue do Redmine"),
    savepath: Param("Caminho para salvar os arquivos", str),
    login: Param("Login Anatel do Usuário", str) = None,
    senha: Param("Senha Utilizada nos Sistemas Interativos da Anatel", str) = None,
    api: Param("Chave API para autenticação. Alternativo ao login e senha", str) = None,
    teste: Param("Indica se o relato será de teste", bool_arg) = True,
):
    download_attachments(issue_obj, savepath, login, senha, api, teste)


def download_attachments(
    issue_obj: Union[str, int],
    savepath: Union[str, Path],
    login: str = None,
    senha: str = None,
    api: str = None,
    teste: bool = True,
):  # sourcery skip: remove-unnecessary-cast
    attachments = extract_attachments(issue_obj, login, senha, api, teste=teste)
    savepath = Path(f"{savepath}/{issue_obj}")
    savepath.mkdir(exist_ok=True)
    attachments.map(lambda attach: _download_attachment(attach, savepath))


def extract_attachments(
    issue_obj: Union[str, int, Issue],
    login: str = None,
    senha: str = None,
    api: str = None,
    fiscaliza: Redmine = None,
    teste: bool = True,
):  # sourcery skip: remove-unnecessary-cast
    attachments = L()
    fiscaliza = valida_fiscaliza(login, senha, api, fiscaliza, teste)
    if not isinstance(issue_obj, Issue) and isinstance(issue_obj, (str, int)):
        issue_obj = fiscaliza.issue.get(issue_obj, include=["relations", "attachments"])

    if (
        getattr(getattr(issue_obj, "tracker", None), "name", None)
        == "Atividade de Inspeção"
    ):
        attachments.extend(getattr(issue_obj, "attachments", []))
        return attachments

    if relations := getattr(issue_obj, "relations", []):
        relations = (
            L(relations).map(dict).filter(lambda r: r["issue_to_id"] == issue_obj.id)
        )
        for r in relations:
            issue_obj = fiscaliza.issue.get(
                r["issue_id"], include=["relations", "attachments"]
            )

            if (
                tipo := getattr(getattr(issue_obj, "tracker", None), "name", None)
            ) == "Ação de Inspeção":
                attachments.extend(extract_attachments(issue_obj, fiscaliza=fiscaliza))
            elif tipo == "Atividade de Inspeção":
                attachments.extend(getattr(issue_obj, "attachments", []))
    return attachments