#!/usr/bin/env python3
"""Writing Coach — Structured essay feedback for high school students.
Ron Paul Curriculum / homeschool aligned. No API, no internet.
"""

import argparse
import json
import re
import sys
from datetime import datetime
from pathlib import Path

DATA_DIR = Path.home() / ".openclaw/workspace/data/writing-coach"
HISTORY_FILE = DATA_DIR / "history.json"

# ─── Helpers ───────────────────────────────────────────────────────────────────

def read_text(path):
    try:
        return Path(path).read_text(errors="replace")
    except FileNotFoundError:
        print(f"ERROR: File not found: {path}")
        sys.exit(1)

def split_paragraphs(text):
    paras = [p.strip() for p in re.split(r'\n\s*\n', text)]
    return [p for p in paras if len(p) > 20]

def split_sentences(text):
    return re.split(r'(?<=[.!?])\s+', text.strip())

def word_count(text):
    return len(text.split())

# ─── Checks ───────────────────────────────────────────────────────────────────

def check_structure(text, paras):
    findings = []
    score = 0
    max_score = 5

    n = len(paras)
    if n == 0:
        findings.append("❌ No paragraphs detected. Make sure your essay has blank lines between paragraphs.")
        return findings, 0, max_score

    # Count check
    if n < 3:
        findings.append(f"⚠️  Only {n} paragraph(s) found. A complete essay needs at least 3 (intro, body, conclusion).")
    elif n == 3:
        findings.append("✅ 3 paragraphs (intro-body-conclusion structure detected).")
        score += 1
    elif n >= 5:
        findings.append(f"✅ {n} paragraphs — good length for a full essay.")
        score += 1

    # Intro check: short, ends with possible thesis
    intro = paras[0]
    intro_sentences = split_sentences(intro)
    if len(intro_sentences) >= 2:
        findings.append("✅ Introduction has multiple sentences.")
        score += 1
    else:
        findings.append("⚠️  Introduction seems short. Aim for 3-5 sentences that lead into your thesis.")

    # Thesis check: last sentence of intro tends to be thesis
    thesis_candidate = intro_sentences[-1] if intro_sentences else ""
    if len(thesis_candidate.split()) > 8 and not thesis_candidate.lower().startswith("in this"):
        findings.append(f"✅ Possible thesis: \"{thesis_candidate[:90]}...\"")
        score += 1
    else:
        findings.append("⚠️  Thesis may be weak or missing. Your last intro sentence should state your main argument clearly.")

    # Body paragraphs: each should start with a topic sentence
    body = paras[1:-1] if n > 2 else []
    weak_topics = 0
    for i, para in enumerate(body, 2):
        sents = split_sentences(para)
        first = sents[0] if sents else ""
        if len(first.split()) < 6:
            weak_topics += 1
    if weak_topics == 0 and body:
        findings.append("✅ Body paragraphs appear to have topic sentences.")
        score += 1
    elif weak_topics > 0:
        findings.append(f"⚠️  {weak_topics} body paragraph(s) may have weak topic sentences. Start each with a clear claim.")

    # Conclusion check
    conclusion = paras[-1]
    conc_words = conclusion.lower()
    conclusion_signals = ["in conclusion", "in summary", "therefore", "thus", "overall", "in the end", "to summarize"]
    if any(s in conc_words for s in conclusion_signals):
        findings.append("✅ Conclusion uses a closing signal phrase.")
        score += 1
    else:
        findings.append("⚠️  Conclusion may be missing a closing phrase (e.g., 'In conclusion...' or 'Therefore...').")

    return findings, score, max_score


def check_grammar(text, paras):
    findings = []
    score = 0
    max_score = 5
    all_sentences = []
    for p in paras:
        all_sentences.extend(split_sentences(p))

    # Sentence length variety
    lengths = [len(s.split()) for s in all_sentences]
    if lengths:
        avg = sum(lengths) / len(lengths)
        very_long = [s for s in all_sentences if len(s.split()) > 40]
        very_short = [s for s in all_sentences if len(s.split()) < 5]

        if very_long:
            findings.append(f"⚠️  {len(very_long)} very long sentence(s) (40+ words). Break these up for clarity.")
            findings.append(f"     Example: \"{very_long[0][:90]}...\"")
        else:
            findings.append("✅ No overly long sentences detected.")
            score += 1

        if len(very_short) > 2:
            findings.append(f"⚠️  {len(very_short)} very short sentence(s). Fragment risk — check these are complete.")
        else:
            score += 1

    # Passive voice patterns
    passive_pattern = re.compile(r'\b(was|were|is|are|been|being)\s+\w+ed\b', re.IGNORECASE)
    passives = passive_pattern.findall(text)
    if len(passives) > 4:
        findings.append(f"⚠️  {len(passives)} possible passive voice phrases. Try rewriting with active voice.")
    else:
        findings.append("✅ Passive voice is minimal — good active writing.")
        score += 1

    # Weak openers
    weak_openers = re.findall(r'^(?:There is|There are|It is|It was)\b', text, re.MULTILINE | re.IGNORECASE)
    if weak_openers:
        findings.append(f"⚠️  {len(weak_openers)} weak opener(s) ('There is/are', 'It is'). Start with the subject instead.")
    else:
        score += 1

    # Filler phrases
    filler = [
        "in order to", "due to the fact", "it is important to note", "it should be noted",
        "basically", "literally", "very very", "really really", "stuff like", "things like",
        "kind of", "sort of"
    ]
    found_filler = [f for f in filler if f in text.lower()]
    if found_filler:
        findings.append(f"⚠️  Filler phrases found: {', '.join(found_filler[:4])}. Replace with precise language.")
    else:
        findings.append("✅ No common filler phrases detected.")
        score += 1

    return findings, score, max_score


def check_argument(text, paras):
    findings = []
    score = 0
    max_score = 4

    # Evidence signals
    evidence_signals = ["for example", "for instance", "such as", "according to",
                        "studies show", "research shows", "in fact", "specifically",
                        "to illustrate", "this shows", "this demonstrates"]
    found_evidence = [s for s in evidence_signals if s in text.lower()]
    if len(found_evidence) >= 3:
        findings.append(f"✅ Good use of evidence signals: {', '.join(found_evidence[:4])}")
        score += 1
    elif len(found_evidence) > 0:
        findings.append(f"⚠️  Some evidence signals found ({', '.join(found_evidence)}), but aim for more examples in each body paragraph.")
    else:
        findings.append("❌ No evidence signals detected. Each body paragraph should include 'For example...' or 'According to...'")

    # Transition words
    transitions = ["however", "therefore", "furthermore", "in addition", "additionally",
                   "on the other hand", "nevertheless", "consequently", "as a result",
                   "first", "second", "third", "finally", "moreover"]
    found_transitions = [t for t in transitions if t in text.lower()]
    if len(found_transitions) >= 4:
        findings.append(f"✅ Strong transitions used: {', '.join(found_transitions[:4])}")
        score += 2
    elif len(found_transitions) >= 2:
        findings.append(f"✅ Some transitions: {', '.join(found_transitions)}. Adding more will improve flow.")
        score += 1
    else:
        findings.append("⚠️  Few transition words. Use words like 'However', 'Furthermore', 'Therefore' to connect ideas.")

    # Counter-argument (advanced)
    counter_signals = ["although", "while some", "despite", "critics", "opponents", "one might argue", "it could be said"]
    has_counter = any(s in text.lower() for s in counter_signals)
    if has_counter:
        findings.append("✅ Counter-argument detected — excellent critical thinking!")
        score += 1
    else:
        findings.append("💡 Consider adding a counter-argument to strengthen your essay. Acknowledge the other side, then refute it.")

    return findings, score, max_score


def run_checks(text, check_type):
    paras = split_paragraphs(text)
    wc = word_count(text)
    results = {"word_count": wc, "paragraph_count": len(paras), "sections": []}

    if check_type in ("structure", "all"):
        findings, score, max_score = check_structure(text, paras)
        results["sections"].append({
            "name": "📐 Structure & Organization",
            "findings": findings,
            "score": score,
            "max": max_score,
        })

    if check_type in ("grammar", "all"):
        findings, score, max_score = check_grammar(text, paras)
        results["sections"].append({
            "name": "✍️  Grammar & Style",
            "findings": findings,
            "score": score,
            "max": max_score,
        })

    if check_type in ("argument", "all"):
        findings, score, max_score = check_argument(text, paras)
        results["sections"].append({
            "name": "💡 Argument Strength",
            "findings": findings,
            "score": score,
            "max": max_score,
        })

    return results


def print_report(results, filepath):
    wc = results["word_count"]
    pc = results["paragraph_count"]
    total_score = sum(s["score"] for s in results["sections"])
    total_max = sum(s["max"] for s in results["sections"])
    pct = round(total_score / max(total_max, 1) * 100)

    bars = "█" * (pct // 10) + "░" * (10 - pct // 10)

    print(f"\n{'='*56}")
    print(f"  ✍️  Writing Coach Report")
    print(f"  File: {Path(filepath).name}")
    print(f"  Words: {wc}  |  Paragraphs: {pc}")
    print(f"{'='*56}\n")

    for section in results["sections"]:
        s, m = section["score"], section["max"]
        print(f"  {section['name']}  [{s}/{m}]")
        print(f"  {'─'*52}")
        for f in section["findings"]:
            print(f"  {f}")
        print()

    print(f"{'─'*56}")
    print(f"  Overall Score: {total_score}/{total_max}  ({pct}%)")
    print(f"  [{bars}]")

    if pct >= 85:
        print("  🏆 Strong writing — great work!")
    elif pct >= 70:
        print("  👍 Good draft — review the suggestions above.")
    elif pct >= 55:
        print("  📝 Developing — work through each suggestion carefully.")
    else:
        print("  💪 Keep at it — every revision makes it stronger.")

    print(f"{'='*56}\n")

    return total_score, total_max, pct


def save_history(filepath, score, max_score, pct):
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    history = []
    if HISTORY_FILE.exists():
        try:
            history = json.loads(HISTORY_FILE.read_text())
        except Exception:
            pass
    history.append({
        "date": datetime.now().strftime("%Y-%m-%d %H:%M"),
        "file": Path(filepath).name,
        "score": score,
        "max": max_score,
        "pct": pct,
    })
    HISTORY_FILE.write_text(json.dumps(history, indent=2))


def cmd_history():
    if not HISTORY_FILE.exists():
        print("No writing history yet. Run a check first!")
        return
    history = json.loads(HISTORY_FILE.read_text())
    print(f"\n📊 Writing History\n")
    print(f"  {'Date':18s} {'File':30s} {'Score':>8}")
    print(f"  {'─'*60}")
    for h in history[-20:]:
        print(f"  {h['date']:18s} {h.get('file','?')[:28]:30s} {h['score']}/{h['max']} ({h['pct']}%)")
    print()


def main():
    parser = argparse.ArgumentParser(description="Writing Coach — Essay Feedback")
    parser.add_argument("--file", "-f", help="Essay file to analyze")
    parser.add_argument("--check", choices=["structure", "grammar", "argument", "all"], default="all",
                        help="What to check (default: all)")
    parser.add_argument("--report", help="Save report to file")
    parser.add_argument("--history", action="store_true", help="View past reports")
    args = parser.parse_args()

    if args.history:
        cmd_history()
        return

    if not args.file:
        parser.print_help()
        sys.exit(1)

    text = read_text(args.file)
    if word_count(text) < 50:
        print("⚠️  Essay seems very short (under 50 words). Add more content for a full review.")

    results = run_checks(text, args.check)
    score, max_score, pct = print_report(results, args.file)
    save_history(args.file, score, max_score, pct)

    if args.report:
        # Save plain text report
        import io, contextlib
        buf = io.StringIO()
        with contextlib.redirect_stdout(buf):
            print_report(results, args.file)
        Path(args.report).write_text(buf.getvalue())
        print(f"📄 Report saved: {args.report}")


if __name__ == "__main__":
    main()
