"""Member CRUD and query commands."""

from __future__ import annotations

import argparse
import json
import time
from datetime import datetime
from typing import Any, List, Optional

from store_db.db import connect
from store_db.ids import next_id
from store_db.operation_log import commit_with_log, log_read
from store_db.response import emit_error, emit_need_confirm, emit_ok

from store_customer_lib.common import (
    SKILL,
    attach_member_extras,
    delete_blocked,
    validate_birthday_month,
)
from store_customer_lib.query_extras import apply_due_within_days_filter, apply_dynamic_filters


def cmd_member_add(args: argparse.Namespace) -> int:
    t0 = time.perf_counter()
    conn = connect()
    mid = args.member_id or next_id(conn, "M", "store_members")
    tags = args.tags_json or "[]"
    fields = args.fields_json or "{}"
    conn.execute("BEGIN IMMEDIATE")
    try:
        conn.execute(
            """INSERT INTO store_members (id, name, phone, birthday, due_date, note, tags_json, fields_json)
               VALUES (?,?,?,?,?,?,?,?)""",
            (mid, args.name, args.phone or "", args.birthday or "", args.due_date or "", args.note or "", tags, fields),
        )
        conn.execute("INSERT INTO store_wallet (member_id) VALUES (?)", (mid,))
        conn.execute(
            "INSERT INTO store_consumption_log (member_id, visit_count) VALUES (?,0) ON CONFLICT(member_id) DO NOTHING",
            (mid,),
        )
        commit_with_log(
            conn, args, skill=SKILL, command="member-add", op="create", table_name="store_members",
            entity_id=mid, after_json={"member_id": mid}, duration_ms=int((time.perf_counter() - t0) * 1000),
        )
    except Exception:
        conn.rollback()
        raise
    emit_ok({"member_id": mid})
    return 0


def cmd_member_update(args: argparse.Namespace) -> int:
    t0 = time.perf_counter()
    payload = json.loads(args.set)
    conn = connect()
    row = conn.execute("SELECT * FROM store_members WHERE id=? AND status='active'", (args.member_id,)).fetchone()
    if not row:
        emit_error("not_found", {"member_id": args.member_id})
    sets: List[str] = []
    vals: List[Any] = []
    col_map = {
        "name": "name", "phone": "phone", "birthday": "birthday", "due_date": "due_date",
        "note": "note", "tags_json": "tags_json", "fields_json": "fields_json",
    }
    for key, col in col_map.items():
        if key in payload:
            val = payload[key]
            if key in ("tags_json", "fields_json") and not isinstance(val, str):
                val = json.dumps(val, ensure_ascii=False)
            sets.append(f"{col}=?")
            vals.append(val)
    if not sets:
        emit_ok({"member_id": args.member_id})
        return 0
    sets.append("updated_at=datetime('now','localtime')")
    vals.append(args.member_id)
    conn.execute(f"UPDATE store_members SET {', '.join(sets)} WHERE id=?", vals)
    commit_with_log(
        conn, args, skill=SKILL, command="member-update", op="update", table_name="store_members",
        entity_id=args.member_id, duration_ms=int((time.perf_counter() - t0) * 1000),
    )
    emit_ok({"member_id": args.member_id})
    return 0


def _build_member_query(conn, args: argparse.Namespace) -> tuple:
    if args.field_key and not args.field_value:
        emit_error("invalid_query", {"hint": "--field-key requires --field-value"})
    if args.field_value and not args.field_key:
        emit_error("invalid_query", {"hint": "--field-value requires --field-key"})

    birthday_mm: Optional[str] = None
    if args.birthday_month:
        birthday_mm = validate_birthday_month(args.birthday_month)
        if not birthday_mm:
            emit_error("invalid_query", {"birthday_month": args.birthday_month})

    clauses: List[str] = ["1=1"]
    params: List[Any] = []
    active_only = not args.include_deleted
    if active_only:
        clauses.append("status='active'")
    if args.member_id:
        clauses.append("id=?")
        params.append(args.member_id)
    if args.phone:
        clauses.append("phone=?")
        params.append(args.phone)
    if args.name:
        status_sql = " AND status='active'" if active_only else ""
        exact = conn.execute(
            f"SELECT id FROM store_members WHERE name=?{status_sql}",
            (args.name,),
        ).fetchall()
        if len(exact) > 1:
            rows = [dict(r) for r in conn.execute(
                f"SELECT * FROM store_members WHERE name=?{status_sql}",
                (args.name,),
            )]
            emit_error(
                "ambiguous_member",
                {
                    "name": args.name,
                    "candidates": [{"member_id": r["id"], "name": r["name"], "phone": r["phone"]} for r in rows],
                },
            )
        if len(exact) == 1:
            clauses.append("name=?")
            params.append(args.name)
        else:
            clauses.append("name LIKE ?")
            params.append(f"%{args.name}%")
    if args.tag:
        clauses.append("EXISTS (SELECT 1 FROM json_each(tags_json) je WHERE je.value=?)")
        params.append(args.tag)
    if birthday_mm:
        clauses.append("birthday IS NOT NULL AND birthday != '' AND substr(birthday, 6, 2)=?")
        params.append(birthday_mm)
    if args.birthday_today:
        clauses.append("birthday IS NOT NULL AND birthday != '' AND substr(birthday, 6, 5)=?")
        params.append(datetime.now().strftime("%m-%d"))
    if args.field_key:
        clauses.append("json_extract(fields_json, ?)=?")
        params.extend([f'$."{args.field_key}"', args.field_value])
    return clauses, params, active_only


def cmd_member_query(args: argparse.Namespace) -> int:
    t0 = time.perf_counter()
    conn = connect()
    limit = args.limit or 500

    if args.field_key:
        fd = conn.execute(
            "SELECT 1 FROM store_custom_field_defs WHERE entity='member' AND field_key=?",
            (args.field_key,),
        ).fetchone()
        if not fd:
            emit_error("unknown_field_key", {"field_key": args.field_key})

    clauses, params, _ = _build_member_query(conn, args)
    sql = f"SELECT * FROM store_members WHERE {' AND '.join(clauses)} ORDER BY id"
    rows = [dict(r) for r in conn.execute(sql, params)]

    if args.filters_json:
        rows = apply_dynamic_filters(rows, json.loads(args.filters_json))

    if args.due_within_days:
        rows = apply_due_within_days_filter(rows, int(args.due_within_days))

    if args.phone and len(rows) > 1:
        emit_error(
            "ambiguous_member",
            {
                "phone": args.phone,
                "candidates": [{"member_id": r["id"], "name": r["name"], "phone": r["phone"]} for r in rows],
            },
        )

    rows = rows[:limit]
    attach_member_extras(conn, rows, args)
    log_read(
        conn, args, skill=SKILL, command="member-query", table_name="store_members",
        entity_id=args.member_id, duration_ms=int((time.perf_counter() - t0) * 1000),
    )
    emit_ok({"members": rows, "count": len(rows)})
    return 0


def cmd_member_txn_query(args: argparse.Namespace) -> int:
    t0 = time.perf_counter()
    conn = connect()
    q = "SELECT * FROM store_transactions WHERE member_id=?"
    params: List[Any] = [args.member_id]
    if args.type:
        q += " AND type=?"
        params.append(args.type)
    if args.date_from:
        q += " AND substr(created_at, 1, 10) >= ?"
        params.append(args.date_from)
    if args.date_to:
        q += " AND substr(created_at, 1, 10) <= ?"
        params.append(args.date_to)
    q += " ORDER BY created_at DESC LIMIT ?"
    params.append(args.limit or 50)
    rows = [dict(r) for r in conn.execute(q, params)]
    log_read(
        conn, args, skill=SKILL, command="member-txn-query", table_name="store_transactions",
        entity_id=args.member_id, duration_ms=int((time.perf_counter() - t0) * 1000),
    )
    emit_ok({"transactions": rows, "count": len(rows)})
    return 0


def cmd_member_delete(args: argparse.Namespace) -> int:
    if not args.yes:
        emit_need_confirm({"action": "member-delete", "member_id": args.member_id})
        return 0
    t0 = time.perf_counter()
    conn = connect()
    row = conn.execute("SELECT * FROM store_members WHERE id=? AND status='active'", (args.member_id,)).fetchone()
    if not row:
        emit_error("not_found", {"member_id": args.member_id})
    blocked = delete_blocked(conn, args.member_id)
    if blocked:
        emit_error("delete_blocked", {"reason": blocked})
    conn.execute(
        "UPDATE store_members SET status='deleted', updated_at=datetime('now','localtime') WHERE id=?",
        (args.member_id,),
    )
    commit_with_log(
        conn, args, skill=SKILL, command="member-delete", op="update", table_name="store_members",
        entity_id=args.member_id, after_json={"status": "deleted"},
        duration_ms=int((time.perf_counter() - t0) * 1000),
    )
    emit_ok({"member_id": args.member_id, "status": "deleted"})
    return 0


def cmd_member_restore(args: argparse.Namespace) -> int:
    if not args.yes:
        emit_need_confirm({"action": "member-restore", "member_id": args.member_id})
        return 0
    t0 = time.perf_counter()
    conn = connect()
    conn.execute(
        "UPDATE store_members SET status='active', updated_at=datetime('now','localtime') WHERE id=?",
        (args.member_id,),
    )
    commit_with_log(
        conn, args, skill=SKILL, command="member-restore", op="update", table_name="store_members",
        entity_id=args.member_id, after_json={"status": "active"},
        duration_ms=int((time.perf_counter() - t0) * 1000),
    )
    emit_ok({"member_id": args.member_id, "status": "active"})
    return 0
