# -*- coding: utf-8 -*-
# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations

import datetime
import uuid
import json
from itertools import chain
from pathlib import Path
from typing import Optional, Sequence
from unittest import mock

from conda.base.context import Context
from conda.notices.core import get_channel_name_and_urls
from conda.notices.types import ChannelNoticeResponse
from conda.models.channel import get_channel_objs

DEFAULT_NOTICE_MESG = "Here is an example message that will be displayed to users"


def get_test_notices(
    messages: Sequence[str],
    level: Optional[str] = "info",
    created_at: Optional[datetime.datetime] = None,
    expired_at: Optional[datetime.datetime] = None,
) -> dict:
    created_at = created_at or datetime.datetime.now(datetime.timezone.utc)
    expired_at = expired_at or created_at + datetime.timedelta(days=7)

    return {
        "notices": list(
            {
                "id": str(uuid.uuid4()),
                "message": message,
                "level": level,
                "created_at": created_at.isoformat(),
                "expired_at": expired_at.isoformat(),
            }
            for message in messages
        )
    }


def add_resp_to_mock(
    mock_session: mock.MagicMock,
    status_code: int,
    messages_json: dict,
    raise_exc: bool = False,
) -> None:
    """Adds any number of MockResponse to MagicMock object as side_effects"""

    def forever_404():
        while True:
            yield MockResponse(404, {})

    def one_200():
        yield MockResponse(status_code, messages_json, raise_exc=raise_exc)

    chn = chain(one_200(), forever_404())
    mock_session.side_effect = tuple(next(chn) for _ in range(100))


def create_notice_cache_files(
    cache_dir: Path,
    cache_files: Sequence[str],
    messages_json_seq: Sequence[dict],
) -> None:
    """Creates the cache files that we use in tests"""
    for message_json, file in zip(messages_json_seq, cache_files):
        cache_key = cache_dir.joinpath(file)
        with open(cache_key, "w") as fp:
            json.dump(message_json, fp)


class DummyArgs:
    """
    Dummy object that sets all kwargs as object properties
    """

    def __init__(self, **kwargs):
        self.no_ansi_colors = True

        for key, val in kwargs.items():
            setattr(self, key, val)


def notices_decorator_assert_message_in_stdout(
    captured, messages: Sequence[str], dummy_mesg: Optional[str] = None, not_in: bool = False
):
    """
    Tests a run of notices decorator where we expect to see the messages
    print to stdout.
    """
    assert captured.err == ""
    assert dummy_mesg in captured.out

    for mesg in messages:
        if not_in:
            assert mesg not in captured.out
        else:
            assert mesg in captured.out


class MockResponse:
    def __init__(self, status_code, json_data, raise_exc=False):
        self.status_code = status_code
        self.json_data = json_data
        self.raise_exc = raise_exc

    def json(self):
        if self.raise_exc:
            raise ValueError("Error")
        return self.json_data


def get_notice_cache_filenames(ctx: Context) -> tuple[str]:
    """Returns the filenames of the cache files that will be searched for"""
    channel_urls_and_names = get_channel_name_and_urls(get_channel_objs(ctx))

    return tuple(
        ChannelNoticeResponse.get_cache_key(url, name, Path("")).name
        for url, name in channel_urls_and_names
    )
