"""Project CRUD routes."""
import logging
import os
import re
from datetime import datetime
from pathlib import Path
from urllib.parse import urlparse

from flask import Blueprint, jsonify, request

from core.db import get_db
from core.decorators import with_project
from core.helpers import run_git, write_json
from core.i18n import t
from core.paths import DEFAULT_GIT_RULES
from services.advance_mode_service import seed_default_modes
from services.configurator_service import ConfiguratorChain
from services.project_settings_service import ProjectSettingsError, get_simple_planning, set_simple_planning

log = logging.getLogger(__name__)

bp = Blueprint("projects", __name__)


@bp.route("/api/projects", methods=["GET"])
def list_projects():
    db = get_db()
    try:
        rows = db.execute("SELECT id, name, path, registered FROM projects ORDER BY registered").fetchall()
        projects = [dict(row) for row in rows]
        return jsonify({"projects": projects})
    finally:
        db.close()


@bp.route("/api/projects", methods=["POST"])
def register_project():
    body = request.get_json(silent=True) or {}
    path = body.get("path", "").strip()
    name = body.get("name", "").strip()

    if not path or not os.path.isdir(path):
        return jsonify({"error": t("api.error.invalidDirectoryPath")}), 400

    ok, _, _ = run_git(path, "rev-parse", "--git-dir")
    if not ok:
        run_git(path, "init")
        run_git(path, "checkout", "-b", "develop")
        gitignore = Path(path) / ".gitignore"
        if not gitignore.exists():
            gitignore.write_text("")
        run_git(path, "add", ".gitignore")
        run_git(path, "commit", "-m", "Initial commit")

    if not name:
        name = os.path.basename(path)

    project_id = re.sub(r'[^a-zA-Z0-9_-]', '-', name.lower())

    db = get_db()
    try:
        existing = db.execute("SELECT id, name, path, registered FROM projects WHERE path = ?", (path,)).fetchone()
        if existing:
            return jsonify({"error": t("api.error.projectAlreadyRegistered"), "project": dict(existing)}), 409

        registered = datetime.now().isoformat()
        db.execute(
            "INSERT INTO projects (id, name, path, registered) VALUES (?, ?, ?, ?)",
            (project_id, name, path, registered)
        )
        seed_default_modes(db, project_id)

        _setup_project_configs(path)
        warnings = []
        try:
            results = ConfiguratorChain.default().run(db, project_id, Path(path))
            warnings = [r for r in results if r["action"] != "rendered"]
        except Exception:
            log.exception("Configurator chain failed at register_project; SKILL.md may be stale")

        project = {"id": project_id, "name": name, "path": path, "registered": registered}
        if warnings:
            project["configurator_warnings"] = warnings
        return jsonify(project), 201
    finally:
        db.close()


def _setup_project_configs(project_path):
    provider, host = _detect_git_provider(project_path)

    git_config_path = Path(project_path) / ".claude" / "git-config.json"
    if not git_config_path.exists():
        write_json(git_config_path, {
            "provider": provider,
            "host": host,
            "token": "",
            "default_branch": "develop",
        })

    if provider == "gitlab" and host:
        mcp_path = Path(project_path) / ".mcp.json"
        if not mcp_path.exists():
            write_json(mcp_path, {
                "mcpServers": {
                    "gitlab": {
                        "command": "npx",
                        "args": ["-y", "@zereight/mcp-gitlab"],
                        "env": {
                            "GITLAB_PERSONAL_ACCESS_TOKEN": "",
                            "GITLAB_API_URL": f"https://{host}/api/v4",
                        },
                    }
                }
            })

    _ensure_git_rules_symlink(project_path)


def _detect_git_provider(project_path):
    ok, stdout, _ = run_git(project_path, "remote", "get-url", "origin")
    if not ok or not stdout.strip():
        return "local", ""

    remote_url = stdout.strip()

    if "gitlab" in remote_url:
        host = _extract_host(remote_url)
        return "gitlab", host

    if "github" in remote_url:
        host = _extract_host(remote_url)
        return "github", host

    return "local", ""


def _extract_host(remote_url):
    if remote_url.startswith("http://") or remote_url.startswith("https://"):
        return urlparse(remote_url).hostname or ""
    if remote_url.startswith("git@"):
        match = re.match(r"git@([^:]+):", remote_url)
        return match.group(1) if match else ""
    return ""


def _ensure_git_rules_symlink(project_path):
    rules_path = Path(project_path) / ".claude" / "git-rules.md"
    if rules_path.exists() or rules_path.is_symlink():
        return

    system_default = DEFAULT_GIT_RULES
    if not system_default.exists():
        return

    rules_path.parent.mkdir(parents=True, exist_ok=True)
    rules_path.symlink_to(system_default)


@bp.route("/api/projects/<project_id>/settings", methods=["GET"])
@with_project
def get_project_settings(db, project):
    simple_planning = get_simple_planning(db, project["id"])
    return jsonify({"simple_planning": simple_planning})


@bp.route("/api/projects/<project_id>/settings", methods=["PUT"])
@with_project
def put_project_settings(db, project):
    body = request.get_json(silent=True) or {}
    if "simple_planning" not in body:
        return jsonify({"error": "simple_planning field is required"}), 400
    if not isinstance(body["simple_planning"], bool):
        return jsonify({"error": "simple_planning must be a boolean"}), 400

    try:
        set_simple_planning(db, project["id"], body["simple_planning"])
        db.commit()
    except ProjectSettingsError as exc:
        return jsonify({"error": str(exc)}), 404

    warnings = []
    try:
        results = ConfiguratorChain.default().run(db, project["id"], Path(project["path"]))
        warnings = [r for r in results if r["action"] != "rendered"]
    except Exception:
        log.exception("Configurator chain failed at put_project_settings; SKILL.md may be stale")

    response = {"ok": True, "simple_planning": body["simple_planning"]}
    if warnings:
        response["configurator_warnings"] = warnings
    return jsonify(response)


@bp.route("/api/projects/<project_id>", methods=["DELETE"])
def delete_project(project_id):
    db = get_db()
    try:
        db.execute("DELETE FROM projects WHERE id = ?", (project_id,))
        db.commit()
        return jsonify({"ok": True})
    finally:
        db.close()
