# -*- coding: utf-8 -*-
"""中台：文件下载（KA连锁/中小连锁/单体药店/C端平台 4 分类，各自配可见范围 + 上传/删除文件）。"""
import os
import uuid
import json
import datetime

from flask import render_template, request, redirect, url_for, flash, current_app
from flask_login import login_required, current_user

from app.models import (DownloadCategory, DownloadCategoryParticipant, DownloadFile,
                        Chain, Staff, Store)
from app.extensions import db
from app.admin import bp
from app.admin.views import _admin_only
from app.services import log_action
from app.region_data import CHINA_REGION

ALLOWED_DL = {"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx",
              "zip", "rar", "7z", "png", "jpg", "jpeg", "gif", "txt", "csv", "mp4"}


def _dl_path(df):
    url = df.file_url or ""
    rel = url[len("/uploads/"):] if url.startswith("/uploads/") else url.lstrip("/")
    return os.path.join(current_app.config["UPLOAD_DIR"], rel)


@bp.route("/downloads")
@login_required
def downloads():
    """文件下载主页：各分类文件列表 + 上传（可见范围在 /downloads/settings 统一配置）。"""
    _admin_only()
    cats = DownloadCategory.query.order_by(
        DownloadCategory.sort.desc(), DownloadCategory.id).all()
    chain = request.args.get("chain", type=int)
    cat_data = []
    for cat in cats:
        files_q = cat.files.order_by(DownloadFile.pinned.desc(), DownloadFile.pinned_at.desc(), DownloadFile.id.desc())
        if cat.key == "ka" and chain:
            files_q = files_q.filter(DownloadFile.chain_id == chain)
        cat_data.append({
            "cat": cat,
            "sel_chains": set(json.loads(cat.allowed_chains) if cat.allowed_chains else []),
            "sel_staff": set(p.staff_id for p in
                             DownloadCategoryParticipant.query.filter_by(category_id=cat.id).all()),
            "files": files_q.all(),
        })
    chains = Chain.query.order_by(Chain.name).all()
    ka = DownloadCategory.query.filter_by(key="ka").first()
    return render_template("admin/downloads.html", cat_data=cat_data, chains=chains, chain=chain,
                           ka_cat_id=(ka.id if ka else 0), active="downloads")


@bp.route("/downloads/settings")
@login_required
def downloads_settings():
    """文件下载可见范围设置：各分类各自的可见范围（全员/按连锁/指定人员）。"""
    _admin_only()
    cats = DownloadCategory.query.order_by(
        DownloadCategory.sort.desc(), DownloadCategory.id).all()
    chains = Chain.query.order_by(Chain.name).all()
    chain_counts = {c.id: Staff.query.join(Staff.store).filter(
        Staff.role == "staff", Staff.deleted.is_(False), Staff.status == "active",
        Store.chain_id == c.id).count() for c in chains}
    staff_list = Staff.query.filter(
        Staff.role == "staff", Staff.deleted.is_(False), Staff.status == "active"
    ).order_by(Staff.id.desc()).limit(500).all()
    cat_data = []
    for cat in cats:
        cat_data.append({
            "cat": cat,
            "sel_chains": set(json.loads(cat.allowed_chains) if cat.allowed_chains else []),
            "sel_staff": set(p.staff_id for p in
                             DownloadCategoryParticipant.query.filter_by(category_id=cat.id).all()),
        })
    return render_template("admin/downloads_settings.html", cat_data=cat_data, chains=chains,
                           staff_list=staff_list, chain_counts=chain_counts,
                           china_region=CHINA_REGION, active="downloads")


@bp.route("/downloads/category/<int:id>", methods=["POST"])
@login_required
def downloads_category_scope(id):
    """保存某分类的可见范围（抄考试范围模式：scope_mode + chains + participant 全量替换）。"""
    _admin_only()
    cat = DownloadCategory.query.get_or_404(id)
    cat.scope_mode = request.form.get("scope_mode", "all")
    cat.allowed_chains = (json.dumps([int(c) for c in request.form.getlist("chains")])
                          if cat.scope_mode == "chain" else None)
    DownloadCategoryParticipant.query.filter_by(category_id=cat.id).delete()
    if cat.scope_mode == "staff":
        for sid in request.form.getlist("staff_ids"):
            db.session.add(DownloadCategoryParticipant(category_id=cat.id, staff_id=int(sid)))
    db.session.commit()
    log_action("download_category_scope", target_type="download_category", target_id=cat.id,
               summary="文件下载分类「%s」可见范围：%s" % (cat.name, cat.scope_mode))
    flash("已保存「%s」可见范围" % cat.name, "success")
    return redirect(url_for("admin.downloads_settings") + "#cat-%d" % cat.id)


@bp.route("/downloads/upload", methods=["POST"])
@login_required
def downloads_upload():
    """上传文件到指定分类（存 /uploads/downloads/uuid.ext，保留原名展示）。"""
    _admin_only()
    cat = DownloadCategory.query.get_or_404(request.form.get("category_id", type=int))
    chain_id = request.form.get("chain_id", type=int)
    if cat.key == "ka" and not chain_id:
        flash("上传到「%s」请选择连锁" % cat.name, "danger")
        return redirect(url_for("admin.downloads") + "#cat-%d" % cat.id)
    f = request.files.get("file")
    if not f or not f.filename:
        flash("请选择文件", "danger")
        return redirect(url_for("admin.downloads"))
    ext = f.filename.rsplit(".", 1)[-1].lower() if "." in f.filename else ""
    if ext not in ALLOWED_DL:
        flash("不支持的文件类型（.%s）" % ext, "danger")
        return redirect(url_for("admin.downloads"))
    fn = "downloads/%s.%s" % (uuid.uuid4().hex, ext)
    path = os.path.join(current_app.config["UPLOAD_DIR"], fn)
    os.makedirs(os.path.dirname(path), exist_ok=True)
    f.save(path)
    db.session.add(DownloadFile(
        category_id=cat.id,
        filename=os.path.basename(f.filename),   # 保留原名展示/下载
        file_url="/uploads/" + fn,
        size=os.path.getsize(path),
        uploader_id=current_user.id,
        chain_id=chain_id if cat.key == "ka" else None))
    db.session.commit()
    log_action("download_upload", target_type="download_category", target_id=cat.id,
               summary="上传文件到「%s」：%s" % (cat.name, os.path.basename(f.filename)))
    flash("已上传到「%s」" % cat.name, "success")
    return redirect(url_for("admin.downloads") + "#cat-%d" % cat.id)


@bp.route("/downloads/<int:fid>/delete", methods=["POST"])
@login_required
def downloads_delete(fid):
    """删除文件（DB 记录 + 磁盘文件）。"""
    _admin_only()
    df = DownloadFile.query.get_or_404(fid)
    cat_id = df.category_id
    path = _dl_path(df)
    if os.path.isfile(path):
        try:
            os.remove(path)
        except OSError:
            pass
    name = df.filename
    db.session.delete(df)
    db.session.commit()
    log_action("download_delete", target_type="download_file", target_id=fid,
               summary="删除下载文件：%s" % name)
    flash("已删除", "success")
    return redirect(url_for("admin.downloads") + "#cat-%d" % cat_id)


@bp.route("/downloads/<int:fid>/move", methods=["POST"])
@login_required
def downloads_move(fid):
    """移动文件到其他分类（仅改 category_id；磁盘文件不动）。"""
    _admin_only()
    df = DownloadFile.query.get_or_404(fid)
    target = request.form.get("target_cat", type=int)
    cat = DownloadCategory.query.get_or_404(target) if target else None
    if not cat:
        flash("请选择目标分类", "danger")
        return redirect(url_for("admin.downloads") + "#cat-%d" % df.category_id)
    chain_id = request.form.get("chain_id", type=int)
    if cat.key == "ka" and not chain_id:
        flash("移动到「%s」请选择连锁" % cat.name, "danger")
        return redirect(url_for("admin.downloads") + "#cat-%d" % df.category_id)
    old_name = df.category.name if df.category else "?"
    filename = df.filename
    df.category_id = cat.id
    df.chain_id = chain_id if cat.key == "ka" else None
    db.session.commit()
    log_action("download_move", target_type="download_file", target_id=fid,
               summary="移动文件「%s」：%s → %s" % (filename, old_name, cat.name))
    flash("已移动「%s」到「%s」" % (filename, cat.name), "success")
    return redirect(url_for("admin.downloads") + "#cat-%d" % cat.id)


@bp.route("/downloads/<int:fid>/rename", methods=["POST"])
@login_required
def downloads_rename(fid):
    """重命名文件（仅改展示文件名 filename，磁盘文件 file_url 不动）。"""
    _admin_only()
    df = DownloadFile.query.get_or_404(fid)
    name = request.form.get("filename", "").strip()
    if not name:
        flash("文件名不能为空", "danger")
        return redirect(url_for("admin.downloads") + "#cat-%d" % df.category_id)
    old = df.filename
    df.filename = name
    db.session.commit()
    log_action("download_rename", target_type="download_file", target_id=fid,
               summary="重命名文件：%s → %s" % (old, name))
    flash("已重命名为「%s」" % name, "success")
    return redirect(url_for("admin.downloads") + "#cat-%d" % df.category_id)


@bp.route("/downloads/<int:fid>/pin", methods=["POST"])
@login_required
def downloads_pin(fid):
    """切换文件置顶（置顶=在后台/H5 列表里排到最前；再次点击取消）。
       多个置顶文件按置顶时间倒序（最后置顶的排最前）。"""
    _admin_only()
    df = DownloadFile.query.get_or_404(fid)
    df.pinned = not df.pinned
    df.pinned_at = datetime.datetime.now() if df.pinned else None
    cat_id = df.category_id
    db.session.commit()
    log_action("download_file_pin" if df.pinned else "download_file_unpin",
               target_type="download_file", target_id=fid,
               summary="%s置顶文件：%s" % ("" if df.pinned else "取消", df.filename))
    flash(("已置顶「%s」（排在最前）" if df.pinned else "已取消置顶「%s」") % df.filename, "success")
    return redirect(url_for("admin.downloads") + "#cat-%d" % cat_id)
