import base64
import datetime as dt
import io

from openpyxl import Workbook, load_workbook

from flyway.models import ShippingParcel


def _b64(data: bytes) -> str:
    return base64.b64encode(data).decode()


def test_parcel_lifecycle(staff_api):
    p = staff_api.post("/api/parcels", json={"barcode": " AB1 ", "comment": "Port A"}).json()
    assert p["barcode"] == "AB1" and not p["is_shipped"] and p["operator_name"] == "Sam (sam)"
    dup = staff_api.post("/api/parcels", json={"barcode": "ab1"})
    assert dup.status_code == 400 and dup.json()["field"] == "barcode"
    assert staff_api.get("/api/parcels/locate", params={"barcode": "ab1 "}).json()["parcel"]["id"] == p["id"]
    assert staff_api.get("/api/parcels/locate", params={"barcode": "nope"}).json() == {"found": False}
    shipped = staff_api.post(f"/api/parcels/{p['id']}/ship").json()
    assert shipped["is_shipped"]
    assert staff_api.get("/api/parcels", params={"status": "shipped"}).json()["total"] == 1
    assert staff_api.get("/api/parcels", params={"status": "active"}).json()["total"] == 0
    # 普通员工可删除包裹（旧系统行为）：先软删、可恢复、再物理删除
    assert staff_api.post("/api/parcels/delete", json={"ids": [p["id"]]}).status_code == 204
    assert staff_api.get("/api/parcels", params={"status": "deleted"}).json()["total"] == 1
    staff_api.post("/api/parcels/restore", json={"ids": [p["id"]]})
    assert staff_api.get("/api/parcels", params={"status": "shipped"}).json()["total"] == 1
    staff_api.post("/api/parcels/delete", json={"ids": [p["id"]], "physical": True})
    assert staff_api.get("/api/parcels", params={"status": "all"}).json()["total"] == 0


def test_import_csv_with_chinese_headers_and_merge(staff_api):
    csv = "程光单号,发货港口/备注,入仓日期\nC1,Auckland,2026-03-02\nC2,,\n".encode("gb18030")
    r = staff_api.post("/api/parcels/import", json={"filename": "a.csv", "content_base64": _b64(csv)}).json()
    assert [p["barcode"] for p in r["imported"]] == ["C1", "C2"] and r["merged"] == []
    c1 = r["imported"][0]
    assert dt.datetime.fromisoformat(c1["created_utc"]) == dt.datetime(2026, 3, 2, tzinfo=dt.UTC)  # 按旧服务器时区（UTC）
    again = "Barcode,Comment,Shipped\nC1,Wellington,2026-03-05 10:00\n".encode()
    skip = staff_api.post("/api/parcels/import", json={"filename": "b.csv", "content_base64": _b64(again)}).json()
    assert skip == {"imported": [], "merged": []}
    merged = staff_api.post("/api/parcels/import", json={"filename": "b.csv", "content_base64": _b64(again),
                                                         "auto_merge": True}).json()["merged"][0]
    assert merged["comment"] == "Wellington" and merged["is_shipped"]


def test_import_xlsx_and_reject_other_files(staff_api):
    wb = Workbook()
    wb.active.append(["单号", "备注", "入库日期"])
    wb.active.append(["X9", "note", dt.datetime(2026, 3, 2, 9, 30)])
    buf = io.BytesIO()
    wb.save(buf)
    r = staff_api.post("/api/parcels/import", json={"filename": "p.XLSX", "content_base64": _b64(buf.getvalue())})
    assert [p["barcode"] for p in r.json()["imported"]] == ["X9"]
    assert staff_api.post("/api/parcels/import", json={"filename": "p.txt", "content_base64": _b64(b"x")}
                          ).status_code == 400
    assert staff_api.post("/api/parcels/import", json={"filename": "p.xlsx", "content_base64": _b64(b"junk")}
                          ).status_code == 400


def test_attention_export_and_dashboard(staff_api, factory):
    staff_api.post("/api/parcels", json={"barcode": "OLD", "comment": "late"})
    staff_api.post("/api/parcels", json={"barcode": "NEW"})
    with factory() as s, s.begin():
        old = s.query(ShippingParcel).filter_by(barcode="OLD").one()
        old.created_utc -= dt.timedelta(days=8)
    d = staff_api.get("/api/dashboard").json()["attention"]
    assert d["count"] == 1 and d["items"][0]["barcode"] == "OLD" and d["items"][0]["needs_attention"]
    assert staff_api.get("/api/parcels", params={"attention": True}).json()["total"] == 1
    x = staff_api.get("/api/parcels/attentions.xlsx")
    sheet = load_workbook(io.BytesIO(x.content)).active
    assert [c.value for c in sheet[1]] == ["程光单号", "发货港口/备注", "入仓日期", "操作员"]
    assert {sheet.cell(r, 1).value for r in (2, 3)} == {"OLD", "NEW"}
