# BSD 2-CLAUSE LICENSE

# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:

# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# #ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Original author: Reza Hosseini

from typing import List

from abvelocity.journey.event.gen_event_query import MultiEventTable, gen_event_query


def gen_event_tables_query(
    multi_event_table: MultiEventTable, start_date: str, end_date: str, create_table_prefix: str
) -> List[str]:
    """
    Generates a list of SQL queries, each extracting one type of event,
    based on a MultiEventTable configuration.

    This function first propagates common information from `multi_event_table.common_info`
    to its individual `event_tables` before generating queries.

    Args:
        multi_event_table (MultiEventTable): An instance containing a list of EventTable instances
            and optional common information.
        start_date (str): The start date for filtering records (e.g., 'YYYY-MM-DD-00').
        end_date (str): The end date for filtering records (e.g., 'YYYY-MM-DD-00').
        create_table_prefix (str): Prefix for naming any new tables created by the queries.

    Returns:
        List[str]: A list of generated SQL queries.
    """
    # Call propagate_common_info here to apply common defaults before generating queries
    multi_event_table.propogate_common_info()

    query_list = []
    for event_table in multi_event_table.event_tables:
        query = gen_event_query(
            event_table=event_table,
            start_date=start_date,
            end_date=end_date,
            create_table_prefix=create_table_prefix,
        )
        query_list.append(query)
    return query_list


def union_tables_query(
    multi_event_table: MultiEventTable, create_table_prefix: str, order_by: str = ""
) -> str:
    """
    Combines the output tables generated by `gen_event_tables_query` into a single
    union table. The name of the final table will be `f"{create_table_prefix}_union"`.

    This function expects that `gen_event_tables_query` (or a similar process) has
    already run, ensuring that `output_table_name` is set for each EventTable.

    Args:
        multi_event_table (MultiEventTable): An instance containing the EventTable instances
            whose output tables will be unioned.
        create_table_prefix (str): Prefix for naming the final union table.
        order_by (str, optional): An ORDER BY clause to sort the results of the union.
            Defaults to an empty string (no specific order).

    Returns:
        str: A complete SQL query to create a union of all specified tables.

    Raises:
        ValueError: If an EventTable does not have an `output_table_name` set,
                    or if no valid tables are found to union.
    """
    query_list = []

    # Build SELECT queries for each table
    for event_table in multi_event_table.event_tables:
        if not event_table.output_table_name:
            raise ValueError(
                f"EventTable with label '{event_table.event_label}' does not have an "
                "output_table_name set. Ensure individual event tables are processed "
                "to set their output names before calling union_tables_query."
            )
        query_list.append(
            f"""
            SELECT * FROM {event_table.output_table_name}
        """
        )

    if not query_list:
        raise ValueError("No event tables with output_table_name found to union.")

    union_table_name = f"{create_table_prefix}_union"
    print(f"Generated union table name will be: {union_table_name}")

    query = f"""
        DROP TABLE IF EXISTS {union_table_name};
        CREATE TABLE IF NOT EXISTS {union_table_name} AS
    """

    # Join the queries with UNION ALL
    query += """
        UNION ALL
    """.join(
        query_list
    )

    # Append the ORDER BY clause if provided
    if order_by:
        query += f" ORDER BY {order_by}"

    return query
