import json
from typing import Any
from models.database import Database
from utils import helpers

class Admin:
    def __init__(self, db: Database):
        self.db = db

    async def get_all_users(self):
        query = "SELECT * FROM users"
        return await self.db.fetchall(query)

    async def get_settings_by_key(self, key: str):
        query = "SELECT * FROM settings WHERE key_name = ?"
        return await self.db.fetchone(query, (key,))

    async def get_variants(self, product_id: int):
        query = "SELECT * FROM variants WHERE product_id = ?"
        return await self.db.fetchall(query, (product_id,))

    async def get_products(self):
        query = "SELECT * FROM products WHERE is_active = 1"
        return await self.db.fetchall(query)

    async def get_product_by_id(self, product_id: int):
        query = "SELECT * FROM products WHERE id = ?"
        return await self.db.fetchone(query, (product_id,))

    async def get_variant_by_id(self, variant_id: int):
        query = "SELECT * FROM variants WHERE id = ?"
        return await self.db.fetchone(query, (variant_id,))

    async def update_variant(self, variant_id: int, column: str, value: Any):
        query = f"UPDATE variants SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, variant_id))

    async def create_order(self, user_id: int, variant_id: int, payment_system: str = None, order_id: str = None):
        query = "INSERT INTO orders (user_id, variant_id, payment_system, order_id) VALUES (?, ?, ?, ?)"
        return await self.db.execute(query, (user_id, variant_id, payment_system, order_id), return_lastrowid=True)

    async def update_order(self, order_id: int, column: str, value: Any):
        query = f"UPDATE orders SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, order_id))

    async def get_order_by_id(self, order_id: int):
        query = "SELECT * FROM orders WHERE id = ?"
        return await self.db.fetchone(query, (order_id,))

    async def generate_unique_order_id(self) -> str:
        while True:
            order_id = helpers.generate_order_id()
            query = "SELECT * FROM orders WHERE order_id = ?"
            existing = await self.db.fetchone(query, (order_id,))
            if not existing:
                return order_id

    async def create_subscriptions(self, user_id: int,
                                   order_id: int,
                                   plan: str,
                                   plan_id: str,
                                   expires_at: str = None,
                                   attributes: dict = None):
        query = "INSERT INTO subscriptions (user_id, order_id, plan, planID, expires_at, attributes) VALUES (?, ?, ?, ?, ?, ?)"
        return await self.db.execute(query, (user_id, order_id, plan, plan_id, expires_at, attributes), return_lastrowid=True)

    async def delete_order_by_id(self, order_id: int):
        query = "DELETE FROM orders WHERE id = ?"
        return await self.db.execute(query, (order_id,))

    async def get_user_by_name(self, username: str):
        query = "SELECT * FROM users WHERE username = ?"
        return await self.db.fetchone(query, (username,))

    async def get_orders_by_user_id(self, user_id: int):
        query = "SELECT * FROM orders WHERE user_id = ?"
        return await self.db.fetchall(query, (user_id,))

    async def get_payments_systems(self):
        query = "SELECT * FROM payments_systems"
        return await self.db.fetchall(query)

    async def update_payment_system(self, payment_system_id: int, column: str, value: Any):
        query = f"UPDATE payments_systems SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, payment_system_id))

    async def get_payment_system_by_id(self, payment_system_id: int):
        query = "SELECT * FROM payments_systems WHERE id = ?"
        return await self.db.fetchone(query, (payment_system_id,))

    async def get_active_payments_systems(self):
        query = "SELECT * FROM payments_systems WHERE is_active = 1"
        return await self.db.fetchall(query)

    async def get_subscriptions_user(self, user_id: int):
        query = "SELECT * FROM subscriptions WHERE user_id = ? AND expires_at > DATETIME('now')"
        return await self.db.fetchall(query, (user_id,))

    async def get_subscription_by_id(self, subscription_id: int):
        query = "SELECT * FROM subscriptions WHERE id = ?"
        return await self.db.fetchone(query, (subscription_id,))\

    async def create_hyperlink(self, hyperlink: str):
        query = "INSERT INTO hyperlinks (link) VALUES (?)"
        return await self.db.execute(query, (hyperlink,), return_lastrowid=True)

    async def get_hyperlink(self, hyperlink: str):
        query = "SELECT * FROM hyperlinks WHERE link = ?"
        return await self.db.fetchone(query, (hyperlink,))

    async def get_hyperlink_by_id(self, hyperlink_id: int):
        query = "SELECT * FROM hyperlinks WHERE id = ?"
        return await self.db.fetchone(query, (hyperlink_id,))

    async def create_hyperlink_user(self, user_id: int, username: str, hyperlink_id: int):
        query = "INSERT INTO hyperlink_users (user_id, username, hyperlink_id) VALUES (?, ?, ?)"
        return await self.db.execute(query, (user_id, username, hyperlink_id), return_lastrowid=True)

    async def update_hyperlink(self, hyperlink_id: int, column: str, value: Any):
        query = f"UPDATE hyperlinks SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, hyperlink_id))

    async def is_hyperlink_user_exits(self, user_id: int, hyperlink_id: int):
        query = "SELECT * FROM hyperlink_users WHERE user_id = ? AND hyperlink_id = ?"
        row = await self.db.fetchone(query, (user_id, hyperlink_id))
        if row:
            return True
        return False

    async def get_all_hyperlinks(self):
        query = "SELECT * FROM hyperlinks"
        return await self.db.fetchall(query)

    async def delete_hyperlink_by_id(self, hyperlink_id: int):
        query = "DELETE FROM hyperlinks WHERE id = ?"
        await self.db.execute(query, (hyperlink_id,))

        second_query = "DELETE FROM hyperlink_users WHERE hyperlink_id = ?"
        return await self.db.execute(second_query, (hyperlink_id,))

    async def get_users_by_hyperlink_id(self, hyperlink_id: int):
        query = "SELECT * FROM hyperlink_users WHERE hyperlink_id = ?"
        return await self.db.fetchall(query, (hyperlink_id,))

    async def get_order_counts_and_totals(self):
        query_users = """
        SELECT 
            (SELECT COUNT(*) FROM users WHERE created_at >= datetime('now', 'start of day')) AS count_1_day,
            (SELECT COUNT(*) FROM users WHERE created_at >= datetime('now', '-7 days')) AS count_7_days,
            (SELECT COUNT(*) FROM users WHERE created_at >= datetime('now', '-30 days')) AS count_30_days,
            (SELECT COUNT(*) FROM users) AS count_all_time
        """

        query_subscriptions = """
        SELECT 
            (SELECT COUNT(*) FROM subscriptions WHERE created_at >= datetime('now', 'start of day')) AS count_1_day,
            (SELECT COUNT(*) FROM subscriptions WHERE created_at >= datetime('now', '-7 days')) AS count_7_days,
            (SELECT COUNT(*) FROM subscriptions WHERE created_at >= datetime('now', '-30 days')) AS count_30_days,
            (SELECT COUNT(*) FROM subscriptions) AS count_all_time
        """

        query_orders = """
        SELECT 
            (SELECT SUM(v.price) FROM orders o
             JOIN variants v ON o.variant_id = v.id  
             WHERE o.created_at >= datetime('now', 'start of day')) AS total_1_day,

            (SELECT SUM(v.price) FROM orders o
             JOIN variants v ON o.variant_id = v.id  
             WHERE o.created_at >= datetime('now', '-7 days')) AS total_7_days,

            (SELECT SUM(v.price) FROM orders o
             JOIN variants v ON o.variant_id = v.id  
             WHERE o.created_at >= datetime('now', '-30 days')) AS total_30_days,

            (SELECT SUM(v.price) FROM orders o
             JOIN variants v ON o.variant_id = v.id) AS total_all_time  
        """

        users_counts = await self.db.fetchone(query_users)
        subscriptions_counts = await self.db.fetchone(query_subscriptions)
        orders_totals = await self.db.fetchone(query_orders)

        return {
            'users': {
                '1_day': users_counts['count_1_day'],
                '7_days': users_counts['count_7_days'],
                '30_days': users_counts['count_30_days'],
                'all_time': users_counts['count_all_time']
            },
            'subscriptions': {
                '1_day': subscriptions_counts['count_1_day'],
                '7_days': subscriptions_counts['count_7_days'],
                '30_days': subscriptions_counts['count_30_days'],
                'all_time': subscriptions_counts['count_all_time']
            },
            'orders': {
                '1_day': orders_totals['total_1_day'] or 0.0,
                '7_days': orders_totals['total_7_days'] or 0.0,
                '30_days': orders_totals['total_30_days'] or 0.0,
                'all_time': orders_totals['total_all_time'] or 0.0
            }
        }

    async def update_subscribe(self, subscribe_id: int, column: str, value: Any):
        query = f"UPDATE subscriptions SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, subscribe_id))

    async def create_promo_discount(self, promo: str, total_activations: int, discount: int):
        query = "INSERT INTO promo_discount (promo, total_activations, discount) VALUES (?, ?, ?)"
        return await self.db.execute(query, (promo, total_activations, discount), return_lastrowid=True)

    async def update_promo_discount(self, promo_id: int, column: str, value: Any):
        query = f"UPDATE promo_discount SET {column} = ? WHERE id = ?"
        return await self.db.execute(query, (value, promo_id))

    async def get_promo_discount_by_promo(self, promo: str):
        query = f"SELECT * FROM promo_discount WHERE promo = ?"
        return await self.db.fetchone(query, (promo,))

    async def create_promo_traffic(self, promo: str, attributes: str):
        query = "INSERT INTO promo_traffic (promo, attributes) VALUES (?, ?)"
        return await self.db.execute(query, (promo, attributes), return_lastrowid=True)

    async def get_promo_traffic_by_promo(self, promo: str):
        query = f"SELECT * FROM promo_traffic WHERE promo = ?"
        return await self.db.fetchone(query, (promo,))

    async def get_product_by_name(self, product_name: str):
        query = "SELECT * FROM products WHERE name = ?"
        return await self.db.fetchone(query, (product_name,))

    async def use_promo_traffic(self, user_id: int, promo_id: int):
        query = "INSERT INTO promo_activates (user_id, promo_id) VALUES (?, ?)"
        return await self.db.execute(query, (user_id, promo_id), return_lastrowid=True)

    async def is_promo_traffic_active_exits(self, promo_id: int):
        query = f"SELECT * FROM promo_activates WHERE promo_id = ?"
        return await self.db.fetchone(query, (promo_id,))