"""Retire a duplicate article: re-point its questions, trash it, claim for the keeper.

Retire means the editorial trash, not deletion — `deleted_at`, which is what
the route does for anything that has been published. Everything behind it
survives: a learner's note on a section, the revisions, the figures.

`--apply` to write. Without it nothing is written and it prints what would be.
"""
import sys
from datetime import datetime

from sqlalchemy import text as sa_text

from app.database import SessionLocal
from app.models.article import Article, ArticleTopicClaim, QuestionArticleLink
from app.services import topic_claims

APPLY = "--apply" in sys.argv

#: category, keep, retire — the other session's decisions. The three it asked
#: to hold are not here.
PAIRS = [
    (15935, 110, 129), (15151, 133, 348), (15060, 195, 288), (15958, 422, 278),
    (15443, 356, 322), (14933, 161, 99), (15041, 88, 204), (15936, 137, 177),
    (15084, 169, 365), (15107, 298, 371), (15029, 308, 217), (15046, 304, 287),
    (14903, 101, 84), (15987, 220, 428), (15038, 154, 257), (15320, 388, 318),
    (14979, 225, 315), (15464, 378, 228), (15025, 132, 270),
]
#: Not a duplicate: a hub and a detail article. Claim for the hub, keep both.
CLAIM_ONLY = [(15290, 91)]

db = SessionLocal()


def category_of(article_id):
    row = db.get(Article, article_id)
    return row.category_id if row else None


moved = trashed = claimed = 0
for category_id, keep, retire in PAIRS:
    keeper, goner = db.get(Article, keep), db.get(Article, retire)
    if not keeper or not goner:
        print(f"!! missing article in pair keep={keep} retire={retire}")
        continue
    if goner.deleted_at is not None:
        print(f"   {retire} already trashed")
        continue

    links = db.query(QuestionArticleLink).filter_by(article_id=retire).all()
    already = {row.question_id for row in
               db.query(QuestionArticleLink.question_id).filter_by(article_id=keep).all()}
    repoint = [row for row in links if row.question_id not in already]
    drop = [row for row in links if row.question_id in already]
    print(f"{goner.title[:34]:34} -> {keeper.title[:30]:30} "
          f"repoint {len(repoint)}, drop-as-duplicate {len(drop)}")
    moved += len(repoint)

    if APPLY:
        for row in repoint:
            # Re-pointed rather than remade, so created_at and who made it
            # survive the move. The section is cleared: a section id from the
            # retired article means nothing in the keeper, and link_sections
            # will put the right one back.
            row.article_id = keep
            row.section_id = None
        for row in drop:
            db.delete(row)
        goner.deleted_at = datetime.utcnow()
        # A claim held by a trashed article would be swept back to life.
        db.query(ArticleTopicClaim).filter_by(article_id=retire).delete()
        db.commit()
        trashed += 1

for category_id, keep in [(c, k) for c, k, _ in PAIRS] + CLAIM_ONLY:
    if not APPLY:
        continue
    claim = db.query(ArticleTopicClaim).filter_by(
        article_id=keep, category_id=category_id, section_id=None).first()
    if claim is None:
        claim = ArticleTopicClaim(article_id=keep, category_id=category_id,
                                  section_id=None, include_subtopics=True,
                                  fill_only=True, user_id=None)
        db.add(claim)
        db.commit()
        db.refresh(claim)
    claimed += topic_claims.apply(db, claim)

print(f"\nrepointed {moved}, trashed {trashed}, newly linked by claims {claimed}, applied {APPLY}")
db.close()
