#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File:                Ampel-core/ampel/mongo/query/general.py
# License:             BSD-3-Clause
# Author:              valery brinnel <firstname.lastname@gmail.com>
# Date:                11.12.2019
# Last Modified Date:  17.02.2021
# Last Modified By:    valery brinnel <firstname.lastname@gmail.com>

from typing import Any, Literal

from bson.int64 import Int64

from ampel.model.operator.AllOf import AllOf
from ampel.model.operator.AnyOf import AnyOf
from ampel.model.operator.OneOf import OneOf
from ampel.mongo.schema import apply_excl_schema, apply_schema
from ampel.mongo.utils import maybe_match_array
from ampel.types import ChannelId, StockId, StrictIterable, Tag

type_stock_id = (int, Int64, bytes, str)


def build_general_query(
	stock: None | StockId | StrictIterable[StockId] = None,
	channel: None | ChannelId | dict | AllOf[ChannelId] | AnyOf[ChannelId] | OneOf[ChannelId] = None,
	tag: None | dict[Literal['with', 'without'], Tag | dict | AllOf[Tag] | AnyOf[Tag] | OneOf[Tag]] = None
) -> dict[str, Any]:
	"""
	Builds a query usable with the ampel "stock", "t0" (with channel=None), "t1" and "t2" collections
	:param stock: matching multiple ids with a single query is possible
	:param channel: None (no criterium) means all channel are considered.
	:param tag: tags to be (or not to be) matched by query
	:returns: query dict with matching criteria
	:raises ValueError: apply_schema can raise ValueError in case the provided dict schema structure is unsupported
	"""

	query = {}

	if stock:
		query['stock'] = stock if isinstance(stock, type_stock_id) \
			else maybe_match_array(stock)

	if channel:
		apply_schema(query, 'channel', channel)

	if tag:

		if 'with' in tag:
			apply_schema(query, 'tag', tag['with'])

		# Order matters, parse_dict(...) must be called *after* parse_excl_dict(...)
		if 'without' in tag:
			apply_excl_schema(query, 'tag', tag['without'])

	return query
