# -*- 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_lock.vendor.conda.base.context import Context
from conda_lock._vendor.conda.notices.core import get_channel_name_and_urls
from conda_lock._vendor.conda.notices.types import ChannelNoticeResponse
from conda_lock._vendor.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, Path("")).name
        for url, name in channel_urls_and_names
    )
