#!/usr/bin/env python3
"""
Client-portal admin CLI (M1). Operator tooling — run inside the terra-view
container against the live DB. The raw magic-link token is shown ONCE on mint;
only its hash is stored.

  # create a client
  python3 backend/portal_admin.py create-client --name "Myler Co" --slug myler [--email dave@x.com]

  # attach a project to a client (sets Project.client_id) — by id, number, or name
  python3 backend/portal_admin.py link-project --slug myler --project-id <PID>
  python3 backend/portal_admin.py link-project --slug myler --project-number 2567-23
  python3 backend/portal_admin.py link-project --slug myler --project-name "RKM Hall"

  # mint-link is RETIRED — per-client magic URLs (/portal/enter) no longer exist.
  #   Client access is now per-PROJECT + password: open the project's page in
  #   Terra-View → "Portal access" to enable it, generate a password, and copy
  #   the /portal/p/<token> link. (create-client / link-project / list / revoke
  #   still operate on the underlying Client/token rows.)

  # list clients, their projects, and active links
  python3 backend/portal_admin.py list

  # revoke a link (stops the link AND any live session it minted)
  python3 backend/portal_admin.py revoke --token-id <TID>
"""

import os
import sys
import uuid
import argparse
from datetime import datetime

# Allow `python3 backend/portal_admin.py ...` (which puts backend/ on sys.path[0],
# hiding the `backend` package) in addition to `python3 -m backend.portal_admin`.
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from backend.database import SessionLocal
from backend.models import Client, ClientAccessToken, Project


def _get_client(db, slug):
    c = db.query(Client).filter_by(slug=slug).first()
    if not c:
        sys.exit(f"No client with slug '{slug}'. Create it first.")
    return c


def create_client(args):
    db = SessionLocal()
    try:
        if db.query(Client).filter_by(slug=args.slug).first():
            sys.exit(f"A client with slug '{args.slug}' already exists.")
        c = Client(id=str(uuid.uuid4()), name=args.name, slug=args.slug,
                   contact_email=args.email, active=True)
        db.add(c)
        db.commit()
        print(f"✓ Created client '{c.name}' (slug={c.slug}, id={c.id})")
        print("  Next: link-project, then mint-link.")
    finally:
        db.close()


def link_project(args):
    db = SessionLocal()
    try:
        c = _get_client(db, args.slug)
        q = db.query(Project)
        if args.project_id:
            p = q.filter_by(id=args.project_id).first()
        elif args.project_number:
            p = q.filter_by(project_number=args.project_number).first()
        elif args.project_name:
            p = q.filter_by(name=args.project_name).first()
        else:
            sys.exit("Specify --project-id, --project-number, or --project-name.")
        if not p:
            sys.exit("Project not found.")
        p.client_id = c.id
        db.commit()
        print(f"✓ Linked project '{p.name}' (id={p.id}) -> client '{c.name}'")
    finally:
        db.close()


def mint_link(args):
    # Retired: the per-client magic URL (/portal/enter/...) was removed when the
    # portal moved to per-project + password access. Minting a token here would
    # only produce a dead link.
    sys.exit(
        "mint-link is retired: per-client magic URLs (/portal/enter/...) no longer exist.\n"
        "Client access is now per-project + password. In Terra-View, open the project's page →\n"
        "'Portal access' to enable the portal, generate a password, and copy the /portal/p/<token>\n"
        "link to send the client."
    )


def revoke(args):
    db = SessionLocal()
    try:
        tok = db.query(ClientAccessToken).filter_by(id=args.token_id).first()
        if not tok:
            sys.exit("No token with that id.")
        if tok.revoked_at:
            print("○ Already revoked.")
            return
        tok.revoked_at = datetime.utcnow()
        db.commit()
        print(f"✓ Revoked token {tok.id} — the link and any live sessions it minted are dead.")
    finally:
        db.close()


def list_all(args):
    db = SessionLocal()
    try:
        clients = db.query(Client).order_by(Client.name).all()
        if not clients:
            print("No clients yet.")
            return
        for c in clients:
            state = "" if c.active else " [INACTIVE]"
            print(f"\n● {c.name}  (slug={c.slug}){state}")
            projs = db.query(Project).filter_by(client_id=c.id).all()
            print("  projects: " + (", ".join(p.name for p in projs) or "(none linked)"))
            toks = db.query(ClientAccessToken).filter_by(client_id=c.id).all()
            if not toks:
                print("  links: (none — run mint-link)")
            for t in toks:
                status = "revoked" if t.revoked_at else "active"
                last = t.last_used_at.strftime("%Y-%m-%d %H:%M") if t.last_used_at else "never used"
                print(f"  link {t.id}  [{status}]  {t.label or ''}  (last: {last})")
        print()
    finally:
        db.close()


def main():
    ap = argparse.ArgumentParser(description="Client-portal admin (M1)")
    sub = ap.add_subparsers(dest="cmd", required=True)

    p = sub.add_parser("create-client"); p.add_argument("--name", required=True)
    p.add_argument("--slug", required=True); p.add_argument("--email"); p.set_defaults(fn=create_client)

    p = sub.add_parser("link-project"); p.add_argument("--slug", required=True)
    p.add_argument("--project-id"); p.add_argument("--project-number"); p.add_argument("--project-name")
    p.set_defaults(fn=link_project)

    p = sub.add_parser("mint-link"); p.add_argument("--slug", required=True)
    p.add_argument("--label"); p.set_defaults(fn=mint_link)

    p = sub.add_parser("revoke"); p.add_argument("--token-id", required=True); p.set_defaults(fn=revoke)

    p = sub.add_parser("list"); p.set_defaults(fn=list_all)

    args = ap.parse_args()
    args.fn(args)


if __name__ == "__main__":
    main()
