"""
Wheeler — сайт + простая CRM на Flask.

Запуск:
    python server.py
Сайт:      http://localhost:8000/
CRM:       http://localhost:8000/crm_bro
Логин:     real_admin1488
Пароль:    adminadmin

Логин/пароль можно переопределить переменными окружения:
    WHEELER_CRM_LOGIN, WHEELER_CRM_PASSWORD
"""

from __future__ import annotations

import hmac
import os
import re
import secrets
import sqlite3
from datetime import datetime, timezone
from functools import wraps
from pathlib import Path

from flask import (
    Flask,
    jsonify,
    redirect,
    render_template,
    request,
    send_from_directory,
    session,
    url_for,
)

BASE_DIR = Path(__file__).resolve().parent
DB_PATH = BASE_DIR / "wheeler_crm.sqlite3"
SECRET_PATH = BASE_DIR / ".crm_secret"

CRM_LOGIN = os.environ.get("WHEELER_CRM_LOGIN", "real_admin1488")
CRM_PASSWORD = os.environ.get("WHEELER_CRM_PASSWORD", "adminadmin")
MAX_LEADS = 50

MANAGERS = ["Менеджер 1", "Менеджер 2", "Менеджер 3", "Менеджер 4"]
CAR_TYPES = {"sedan", "hatchback", "suv", "crossover", "other"}
BUDGETS = {"8-12", "12-20", "20-30", "30+"}
TERMS = {"week", "month", "three-months"}


def _load_secret() -> str:
    env_secret = os.environ.get("WHEELER_SECRET")
    if env_secret:
        return env_secret
    if SECRET_PATH.exists():
        value = SECRET_PATH.read_text(encoding="utf-8").strip()
        if value:
            return value
    value = secrets.token_hex(32)
    SECRET_PATH.write_text(value, encoding="utf-8")
    return value


app = Flask(__name__, static_folder=None, template_folder=str(BASE_DIR))
app.secret_key = _load_secret()
app.config.update(
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE="Lax",
    MAX_CONTENT_LENGTH=64 * 1024,
)


def get_db() -> sqlite3.Connection:
    conn = sqlite3.connect(DB_PATH, timeout=10)
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA busy_timeout=5000")
    return conn


def init_db() -> None:
    conn = get_db()
    try:
        conn.execute(
            """
            CREATE TABLE IF NOT EXISTS leads (
                id         INTEGER PRIMARY KEY AUTOINCREMENT,
                created_at TEXT NOT NULL,
                name       TEXT NOT NULL,
                phone      TEXT NOT NULL,
                car_type   TEXT NOT NULL DEFAULT '',
                budget     TEXT NOT NULL DEFAULT '',
                term       TEXT NOT NULL DEFAULT '',
                comment    TEXT NOT NULL DEFAULT '',
                manager    TEXT NOT NULL DEFAULT ''
            )
            """
        )
        conn.commit()
    finally:
        conn.close()


def login_required(view):
    @wraps(view)
    def wrapper(*args, **kwargs):
        if not session.get("user"):
            if request.path.startswith("/api/"):
                return jsonify(ok=False, error="Потрібна авторизація"), 401
            return redirect(url_for("crm_login"))
        return view(*args, **kwargs)

    return wrapper


# --------------------------------------------------------------------------
# Статические файлы сайта
# --------------------------------------------------------------------------
@app.get("/")
def site_index():
    return send_from_directory(BASE_DIR, "main.html")


@app.get("/styles.css")
def site_css():
    return send_from_directory(BASE_DIR, "styles.css")


@app.get("/script.js")
def site_js():
    return send_from_directory(BASE_DIR, "script.js")


@app.get("/assets/<path:filename>")
def site_assets(filename: str):
    return send_from_directory(BASE_DIR / "assets", filename)


@app.get("/crm.css")
def crm_css():
    return send_from_directory(BASE_DIR, "crm.css")


@app.get("/crm.js")
def crm_js():
    return send_from_directory(BASE_DIR, "crm.js")


# --------------------------------------------------------------------------
# Авторизация
# --------------------------------------------------------------------------
@app.route("/crm_bro/login", methods=["GET", "POST"])
def crm_login():
    if session.get("user"):
        return redirect(url_for("crm_dashboard"))

    error = None
    if request.method == "POST":
        login = (request.form.get("login") or "").strip()
        password = request.form.get("password") or ""
        if hmac.compare_digest(login, CRM_LOGIN) and hmac.compare_digest(
            password, CRM_PASSWORD
        ):
            session.clear()
            session["user"] = login
            return redirect(url_for("crm_dashboard"))
        error = "Невірний логін або пароль"

    return render_template("crm_login.html", error=error)


@app.post("/crm_bro/logout")
@login_required
def crm_logout():
    session.clear()
    return redirect(url_for("crm_login"))


@app.get("/crm_bro")
@login_required
def crm_dashboard():
    return render_template(
        "crm.html",
        managers=MANAGERS,
        max_leads=MAX_LEADS,
    )


# --------------------------------------------------------------------------
# API заявок
# --------------------------------------------------------------------------
@app.post("/api/leads")
def create_lead():
    data = request.get_json(silent=True)
    if not isinstance(data, dict):
        return jsonify(ok=False, error="Некоректні дані"), 400

    name = str(data.get("name", "")).strip()[:80]
    phone = re.sub(r"\D", "", str(data.get("phone", "")))[:15]
    car_type = str(data.get("carType", "")).strip()
    budget = str(data.get("budget", "")).strip()
    term = str(data.get("term", "")).strip()
    comment = str(data.get("comment", "")).strip()[:1000]
    consent = data.get("consent") is True

    if len(name) < 2:
        return jsonify(ok=False, error="Вкажіть ім’я"), 400
    if not (10 <= len(phone) <= 15):
        return jsonify(ok=False, error="Вкажіть коректний телефон"), 400
    if not consent:
        return jsonify(ok=False, error="Потрібна згода на обробку даних"), 400

    car_type = car_type if car_type in CAR_TYPES else ""
    budget = budget if budget in BUDGETS else ""
    term = term if term in TERMS else ""

    created_at = datetime.now(timezone.utc).isoformat(timespec="seconds")

    conn = get_db()
    try:
        cursor = conn.execute(
            """
            INSERT INTO leads (created_at, name, phone, car_type, budget, term, comment)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            """,
            (created_at, name, phone, car_type, budget, term, comment),
        )
        lead_id = cursor.lastrowid
        # Оставляем только последние MAX_LEADS анкет.
        conn.execute(
            "DELETE FROM leads WHERE id NOT IN "
            "(SELECT id FROM leads ORDER BY id DESC LIMIT ?)",
            (MAX_LEADS,),
        )
        conn.commit()
    finally:
        conn.close()

    return jsonify(ok=True, id=lead_id), 201


@app.get("/api/leads")
@login_required
def list_leads():
    conn = get_db()
    try:
        rows = conn.execute(
            "SELECT id, created_at, name, phone, car_type, budget, term, comment, manager "
            "FROM leads ORDER BY id DESC LIMIT ?",
            (MAX_LEADS,),
        ).fetchall()
    finally:
        conn.close()

    return jsonify(
        ok=True,
        leads=[dict(row) for row in rows],
        managers=MANAGERS,
        max_leads=MAX_LEADS,
    )


@app.patch("/api/leads/<int:lead_id>")
@login_required
def update_lead(lead_id: int):
    data = request.get_json(silent=True)
    if not isinstance(data, dict):
        return jsonify(ok=False, error="Некоректні дані"), 400

    manager = str(data.get("manager", "")).strip()
    if manager and manager not in MANAGERS:
        return jsonify(ok=False, error="Невідомий менеджер"), 400

    conn = get_db()
    try:
        cursor = conn.execute(
            "UPDATE leads SET manager = ? WHERE id = ?",
            (manager, lead_id),
        )
        conn.commit()
        updated = cursor.rowcount
    finally:
        conn.close()

    if not updated:
        return jsonify(ok=False, error="Заявку не знайдено"), 404

    return jsonify(ok=True, id=lead_id, manager=manager)


@app.after_request
def security_headers(response):
    response.headers.setdefault("X-Content-Type-Options", "nosniff")
    response.headers.setdefault("Referrer-Policy", "same-origin")
    response.headers.setdefault("X-Frame-Options", "SAMEORIGIN")
    return response


init_db()


if __name__ == "__main__":
    host = os.environ.get("WHEELER_HOST", "0.0.0.0")
    port = int(os.environ.get("WHEELER_PORT", "8000"))
    print(f"Сайт:  http://localhost:{port}/")
    print(f"CRM:   http://localhost:{port}/crm_bro")
    try:
        from waitress import serve

        serve(app, host=host, port=port)
    except ImportError:
        app.run(host=host, port=port)
