from __future__ import annotations

from datetime import datetime
from typing import Any


class AlertRepositoryMixin:
    def save_alert(
        self,
        user_id: int,
        kind: str,
        title: str,
        content: str,
        available_date: str,
        code: str,
        dedupe_key: str,
    ) -> int:
        now = datetime.now().astimezone().isoformat(timespec="seconds")
        with self.connect() as connection:
            connection.execute(
                """
                INSERT INTO alerts
                    (user_id, kind, title, content, available_date, code, dedupe_key,
                     is_read, created_at, updated_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
                ON CONFLICT(user_id, dedupe_key) DO UPDATE SET
                    title=excluded.title, content=excluded.content,
                    available_date=excluded.available_date, updated_at=excluded.updated_at
                """,
                (
                    int(user_id), kind, title, content, available_date, code,
                    dedupe_key, now, now,
                ),
            )
            row = connection.execute(
                "SELECT id FROM alerts WHERE user_id = ? AND dedupe_key = ?",
                (int(user_id), dedupe_key),
            ).fetchone()
        return int(row["id"])

    def list_alerts(
        self, user_id: int, as_of: str, unread_only: bool = False, limit: int = 100
    ) -> list[dict[str, Any]]:
        with self.connect() as connection:
            if unread_only:
                rows = connection.execute(
                    """
                    SELECT id, kind, title, content, available_date, code, is_read,
                           created_at, updated_at, read_at
                    FROM alerts
                    WHERE user_id = ? AND available_date <= ? AND is_read = 0
                    ORDER BY available_date DESC, id DESC LIMIT ?
                    """,
                    (int(user_id), as_of, max(1, min(300, int(limit)))),
                ).fetchall()
            else:
                rows = connection.execute(
                    """
                    SELECT id, kind, title, content, available_date, code, is_read,
                           created_at, updated_at, read_at
                    FROM alerts WHERE user_id = ?
                    ORDER BY CASE WHEN available_date > ? THEN 0 ELSE 1 END,
                             is_read, available_date, id DESC LIMIT ?
                    """,
                    (int(user_id), as_of, max(1, min(300, int(limit)))),
                ).fetchall()
        return [{**dict(row), "is_read": bool(row["is_read"])} for row in rows]

    def count_unread_alerts(self, user_id: int, as_of: str) -> int:
        with self.connect() as connection:
            row = connection.execute(
                """
                SELECT COUNT(*) AS total FROM alerts
                WHERE user_id = ? AND available_date <= ? AND is_read = 0
                """,
                (int(user_id), as_of),
            ).fetchone()
        return int(row["total"] if row else 0)

    def mark_alert_read(self, user_id: int, alert_id: int) -> bool:
        now = datetime.now().astimezone().isoformat(timespec="seconds")
        with self.connect() as connection:
            cursor = connection.execute(
                """
                UPDATE alerts SET is_read = 1, read_at = ?, updated_at = ?
                WHERE id = ? AND user_id = ?
                """,
                (now, now, int(alert_id), int(user_id)),
            )
            return cursor.rowcount > 0

    def mark_all_alerts_read(self, user_id: int, as_of: str) -> int:
        now = datetime.now().astimezone().isoformat(timespec="seconds")
        with self.connect() as connection:
            cursor = connection.execute(
                """
                UPDATE alerts SET is_read = 1, read_at = ?, updated_at = ?
                WHERE user_id = ? AND available_date <= ? AND is_read = 0
                """,
                (now, now, int(user_id), as_of),
            )
            return int(cursor.rowcount)

    def delete_alert(self, user_id: int, alert_id: int) -> bool:
        with self.connect() as connection:
            cursor = connection.execute(
                "DELETE FROM alerts WHERE id = ? AND user_id = ?",
                (int(alert_id), int(user_id)),
            )
            return cursor.rowcount > 0
