# -*- coding: utf-8 -*-
"""跨模块业务服务函数。积分变动统一入口在此，保证余额与流水一致。"""
import datetime

from app.extensions import db
from app.models import Staff, PointsLog, OperationLog


def add_points(staff, delta, ptype, ref_id=None, remark="", commit=True):
    """统一积分变动入口：余额走原子 SQL UPDATE（防并发丢更新）+ 写流水(balance_after)。

    - delta>0 加分：UPDATE staff SET points_balance = points_balance + delta
    - delta<0 扣分：带 WHERE points_balance + delta >= 0 条件，余额不足时更新 0 行
    - commit=False 时不提交，供多步事务在外层统一 commit/rollback（如兑换、审核发分）
    返回 PointsLog；若店员不存在或扣分余额不足（更新 0 行）则返回 None（未改动）。
    """
    staff_id = staff.id if hasattr(staff, "id") else int(staff)
    delta = int(delta)
    if delta == 0:
        return None
    if delta > 0:
        rows = db.session.query(Staff).filter(Staff.id == staff_id).update(
            {Staff.points_balance: Staff.points_balance + delta}, synchronize_session=False)
    else:
        # 仅当扣后余额 >= 0 才更新（原子防超扣/负积分）
        rows = db.session.query(Staff).filter(
            Staff.id == staff_id, Staff.points_balance + delta >= 0).update(
            {Staff.points_balance: Staff.points_balance + delta}, synchronize_session=False)
    if not rows:
        return None
    # 事务内重读最新余额，写入流水 balance_after
    new_bal = db.session.query(Staff.points_balance).filter_by(id=staff_id).scalar() or 0
    log = PointsLog(
        staff_id=staff_id,
        delta=delta,
        type=ptype,
        ref_id=ref_id,
        remark=remark,
        balance_after=new_bal,
    )
    db.session.add(log)
    # 失效内存对象，后续读取 staff.points_balance 会自动重载为最新值（避免读到旧值）
    if hasattr(staff, "__mapper__"):
        db.session.expire(staff)
    if commit:
        db.session.commit()
    return log


def log_action(action, target_type=None, target_id=None, summary="", commit=True):
    """记录中台敏感操作。需在请求上下文内调用（取 current_user / remote_addr）。"""
    from flask import request, has_request_context
    from flask_login import current_user
    admin_id = None
    try:
        admin_id = current_user.id if current_user.is_authenticated else None
    except Exception:
        admin_id = None
    ip = request.remote_addr if has_request_context() else None
    log = OperationLog(
        admin_id=admin_id,
        action=action,
        target_type=target_type,
        target_id=target_id,
        summary=(summary or "")[:500],
        ip=ip,
    )
    db.session.add(log)
    if commit:
        db.session.commit()
    return log


def mask_phone(phone):
    """手机号脱敏：138****1234（沿用 zhishi-game admin.html 逻辑）"""
    if not phone or len(phone) < 8:
        return phone or ""
    return phone[:3] + "****" + phone[-4:]


def calc_like_reward(reward_rules_json, likes):
    """按阶梯奖励规则计算集赞积分：取达到的最高档。
    reward_rules: dict 字符串键(赞数门槛)->积分值，如 {"20":50,"50":100}
    """
    if not reward_rules_json:
        return 0
    import json
    try:
        rules = json.loads(reward_rules_json) if isinstance(reward_rules_json, str) else reward_rules_json
    except Exception:
        return 0
    best = 0
    for k, v in rules.items():
        try:
            if likes >= int(k):
                best = max(best, int(v))
        except (ValueError, TypeError):
            continue
    return best


def get_setting_int(key, default=0):
    """读 Setting 表的整型配置（键不存在/空/非法→默认值）。"""
    from app.models import Setting
    row = Setting.query.get(key)
    try:
        return int(row.value) if row and row.value not in (None, "") else default
    except (ValueError, TypeError):
        return default


def get_setting(key, default=None):
    """读 Setting 表的字符串配置（键不存在/空→default）。"""
    from app.models import Setting
    row = Setting.query.get(key)
    return row.value if row and row.value not in (None, "") else default


def set_setting(key, value):
    """写 Setting 表（value=None→存空串）。供销售看板金额/变更时间等使用。"""
    from app.models import Setting
    v = "" if value is None else str(value)
    row = Setting.query.get(key)
    if row:
        row.value = v
    else:
        db.session.add(Setting(key=key, value=v))
