import os
import re
import sqlite3
from contextlib import closing
from datetime import datetime
from flask import Flask, request, jsonify, g

# Simple (not perfect) email regex. For stricter validation, use `email-validator` package.
EMAIL_REGEX = re.compile(r"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$", re.IGNORECASE)

DB_PATH = os.getenv("DATABASE_PATH", "emails.db")

app = Flask(__name__)


def get_db():
    if "db" not in g:
        conn = sqlite3.connect(DB_PATH)
        conn.row_factory = sqlite3.Row
        with closing(conn.cursor()) as cur:
            # Basic pragmas for better SQLite behavior
            cur.execute("PRAGMA foreign_keys = ON;")
            cur.execute("PRAGMA journal_mode = WAL;")
        g.db = conn
    return g.db


def init_db():
    conn = get_db()
    with closing(conn.cursor()) as cur:
        cur.execute(
            """
            CREATE TABLE IF NOT EXISTS subscribers (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                email TEXT NOT NULL UNIQUE,
                ip TEXT,
                user_agent TEXT,
                created_at TEXT NOT NULL DEFAULT (datetime('now'))
            );
            """
        )
        conn.commit()


with app.app_context():
    # Ensure the database/table exists before handling traffic
    init_db()


@app.teardown_appcontext
def close_db(_e=None):
    db = g.pop("db", None)
    if db is not None:
        db.close()


def normalize_email(email: str) -> str:
    return email.strip().lower()


def is_valid_email(email: str) -> bool:
    return bool(EMAIL_REGEX.match(email))


@app.route("/health", methods=["GET"])
def health():
    return jsonify({"status": "ok"}), 200


@app.route("/stats", methods=["GET"])
def stats():
    db = get_db()
    with closing(db.cursor()) as cur:
        cur.execute("SELECT COUNT(*) AS cnt FROM subscribers;")
        row = cur.fetchone()
    return jsonify({"subscribers": row["cnt"] if row else 0}), 200


@app.route("/subscribe", methods=["POST"])
def subscribe():
    # Accept both HTML form (application/x-www-form-urlencoded or multipart/form-data)
    # and JSON (application/json)
    email = None
    if request.is_json:
        data = request.get_json(silent=True) or {}
        email = data.get("email")
    else:
        email = request.form.get("email")

    if not email:
        return jsonify({"status": "error", "message": "Email is required."}), 400

    email = normalize_email(email)
    if not is_valid_email(email):
        return jsonify({"status": "error", "message": "Invalid email format."}), 400

    ip = request.headers.get("X-Forwarded-For", request.remote_addr or "")
    user_agent = request.headers.get("User-Agent", "")

    db = get_db()
    try:
        with closing(db.cursor()) as cur:
            cur.execute(
                "INSERT INTO subscribers (email, ip, user_agent) VALUES (?, ?, ?)",
                (email, ip, user_agent),
            )
        db.commit()
    except sqlite3.IntegrityError:
        # Unique constraint violation (already subscribed)
        return (
            jsonify(
                {
                    "status": "duplicate",
                    "message": "Email already subscribed.",
                    "email": email,
                }
            ),
            409,
        )

    return (
        jsonify(
            {
                "status": "ok",
                "message": "Subscribed successfully.",
                "email": email,
                "created_at": datetime.utcnow().isoformat() + "Z",
            }
        ),
        201,
    )


if __name__ == "__main__":
    port = int(os.getenv("PORT", "5000"))
    debug = os.getenv("FLASK_DEBUG", "0") == "1"
    app.run(host="0.0.0.0", port=port, debug=debug)
