"""Fake isekai title generator: a word-level Markov chain over every real isekai title.

    python markov.py 40        -> 40 fakes in fakes.txt, each checked against every real title
"""
import random
import sys
from collections import defaultdict
from difflib import SequenceMatcher
from pathlib import Path

import pandas as pd

DATA = Path(__file__).resolve().parent.parent / "data" / "clean"
START, END = "<s>", "</s>"


def corpus():
    frames = [pd.read_csv(DATA / f) for f in ("anime.csv", "novels.csv") if (DATA / f).exists()]
    df = pd.concat(frames)
    df = df[df.isekai & df.has_english & ~df.adult & df.first_season & ~df.sequel_marker.fillna(False).astype(bool)]
    return sorted(set(df[~df.format.isin(["MOVIE", "OVA", "SPECIAL"])].title_english))


def train(titles, order=2):
    chain = defaultdict(list)
    for t in titles:
        words = [START] * order + t.split() + [END]
        for i in range(len(words) - order):
            chain[tuple(words[i:i + order])].append(words[i + order])
    return chain


def generate(chain, order=2, max_words=40):
    state, out = (START,) * order, []
    while len(out) < max_words:
        word = random.choice(chain[state])
        if word == END:
            break
        out.append(word)
        state = state[1:] + (word,)
    return " ".join(out)


def closest(fake, real):
    return max(real, key=lambda r: SequenceMatcher(None, fake.lower(), r.lower()).ratio())


if __name__ == "__main__":
    n = int(sys.argv[1]) if len(sys.argv) > 1 else 20
    real = corpus()
    chain = train(real)
    real_set = {r.lower() for r in real}
    fakes = set()
    while len(fakes) < n:
        f = generate(chain)
        # a copy (or a near copy) of a real title is not a fake
        if f.lower() not in real_set and len(f.split()) >= 6 and SequenceMatcher(None, f.lower(), closest(f, real).lower()).ratio() < 0.85:
            fakes.add(f)
    lines = []
    for f in sorted(fakes, key=len):
        c = closest(f, real)
        lines.append(f"{f}\n    closest real: {c}  ({SequenceMatcher(None, f.lower(), c.lower()).ratio():.2f})")
    (Path(__file__).parent / "fakes.txt").write_text("\n".join(lines), encoding="utf-8")
    print(f"{len(real)} real titles, {len(fakes)} fakes written to fakes.txt")
