#!/usr/bin/python3
"""
Validate Pre-Treatment - Hard Gate Before Treatment Generation

This script validates that a project has completed promotion and has all
required files before treatment.md can be generated. This is a HARD GATE -
treatment generation cannot proceed if this fails.

Required files:
1. bible/episode_arc.md - Must exist with all 60 episodes defined
2. bible/characters.md - Must exist and pass behavioral DNA validation
3. bible/series_bible.md - Must exist with content

Usage: python3 validate_pre_treatment.py <project_path>
Example: python3 validate_pre_treatment.py ./leviathan

Arguments:
  project_path   Path to production project (must have /bible/ folder)

Returns:
- Exit code 0: All prerequisites met, treatment generation may proceed
- Exit code 1: One or more prerequisites missing
- Exit code 2: Configuration/path error
"""

import sys
import re
import subprocess
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent.parent))  # CLAUDE_PROJECTS, for recoil.*
from recoil.core.paths import ProjectPaths


def check_episode_arc(project_path):
    """Check that episode_arc.md exists and has 60 episodes defined."""
    arc_path = project_path / "bible" / "episode_arc.md"

    if not arc_path.exists():
        return {
            'passed': False,
            'error': 'bible/episode_arc.md does not exist',
            'suggestion': 'Run /promote [project] to create the scripting folder structure',
        }

    content = arc_path.read_text()

    # Count episode definitions (looking for patterns like "| 1 |" or "Ep 1:" or "Episode 1")
    episode_patterns = [
        r'\|\s*(\d+)\s*\|',           # Table format: | 1 | ...
        r'Ep(?:isode)?\s+(\d+)',      # Ep 1 or Episode 1
        r'###\s*Episode\s+(\d+)',     # ### Episode 1
    ]

    found_episodes = set()
    for pattern in episode_patterns:
        matches = re.findall(pattern, content, re.IGNORECASE)
        for match in matches:
            ep_num = int(match)
            if 1 <= ep_num <= 60:
                found_episodes.add(ep_num)

    episode_count = len(found_episodes)

    if episode_count < 60:
        missing = [i for i in range(1, 61) if i not in found_episodes]
        missing_str = ', '.join(str(e) for e in missing[:10])
        if len(missing) > 10:
            missing_str += f'... (+{len(missing) - 10} more)'

        return {
            'passed': False,
            'error': f'episode_arc.md has only {episode_count}/60 episodes',
            'missing': missing_str,
            'suggestion': 'Ensure structure_outline.md has all 60 episodes before promotion',
        }

    return {
        'passed': True,
        'episode_count': episode_count,
    }


def check_characters(project_path):
    """Check that characters.md exists and has basic content."""
    # Check both possible locations (characters.md is the new standard)
    chars_path = project_path / "bible" / "characters.md"
    legacy_path = project_path / "bible" / "character_voices.md"

    if chars_path.exists():
        voices_path = chars_path
    elif legacy_path.exists():
        voices_path = legacy_path
    else:
        return {
            'passed': False,
            'error': 'bible/characters.md does not exist',
            'suggestion': 'Run /promote [project] to copy characters.md to bible folder',
        }

    content = voices_path.read_text()

    # Check for character headers (## CHARACTER NAME format)
    header_pattern = re.compile(r'^##\s+([A-Z][A-Za-z0-9\s\-\_]+?)(?:\s*[-—].*)?$', re.MULTILINE)
    characters = header_pattern.findall(content)

    # Filter out non-character headers
    skip_headers = [
        'voice', 'speech', 'dialogue', 'patterns', 'overview',
        'summary', 'notes', 'index', 'table', 'contents',
        'behavioral', 'dna', 'consistency', 'tone', 'humor',
    ]

    character_count = 0
    for char in characters:
        char_lower = char.lower().strip()
        if not any(skip in char_lower for skip in skip_headers):
            character_count += 1

    if character_count == 0:
        return {
            'passed': False,
            'error': 'characters.md has no character sections',
            'suggestion': 'Ensure file has ## CHARACTER NAME headers',
        }

    # Check minimum content length
    if len(content) < 500:
        return {
            'passed': False,
            'error': 'characters.md is too short (minimal content)',
            'suggestion': 'Ensure characters have behavioral DNA, voice patterns, and sample dialogue',
        }

    return {
        'passed': True,
        'character_count': character_count,
    }


def check_fill_placeholders(project_path):
    """Check that no [FILL] placeholders remain in bible documents."""
    bible_path = project_path / "bible"
    if not bible_path.exists():
        return {'passed': True, 'skipped': True}

    fill_files = []
    for md_file in bible_path.glob("*.md"):
        content = md_file.read_text(encoding='utf-8')
        fill_count = content.count('[FILL]')
        if fill_count > 0:
            fill_files.append({
                'file': md_file.name,
                'count': fill_count,
            })

    if fill_files:
        details = ', '.join(f"{f['file']} ({f['count']}x)" for f in fill_files)
        return {
            'passed': False,
            'error': f'[FILL] placeholders remain in bible docs: {details}',
            'suggestion': 'Complete the episode_arc.md filling step in /promote before proceeding',
            'files': fill_files,
        }

    return {'passed': True}


def check_series_bible(project_path):
    """Check that series_bible.md exists with content."""
    bible_path = project_path / "bible" / "series_bible.md"

    if not bible_path.exists():
        return {
            'passed': False,
            'error': 'bible/series_bible.md does not exist',
            'suggestion': 'Run /promote [project] to create series_bible.md from development docs',
        }

    content = bible_path.read_text()

    # Check minimum content length
    if len(content) < 300:
        return {
            'passed': False,
            'error': 'series_bible.md is too short (minimal content)',
            'suggestion': 'Ensure series bible has world, theme, and concept sections',
        }

    return {
        'passed': True,
        'word_count': len(content.split()),
    }


def check_state_folder(project_path):
    """Check that state folder is initialized."""
    state_path = ProjectPaths.from_root(project_path).state_dir
    state_json = state_path / "current_state.json"

    if not state_path.exists():
        return {
            'passed': False,
            'error': 'state/ folder does not exist',
            'suggestion': 'Run /promote [project] to initialize state tracking',
        }

    if not state_json.exists():
        return {
            'passed': False,
            'error': 'state/current_state.json does not exist',
            'suggestion': 'Run /promote [project] to initialize state tracking',
        }

    return {
        'passed': True,
    }


def run_behavioral_dna_validation(project_path):
    """Run the behavioral DNA validator and check its result."""
    validator_path = Path(__file__).parent / "validate_behavioral_dna.py"

    if not validator_path.exists():
        return {
            'passed': True,  # Don't block if validator doesn't exist
            'skipped': True,
            'note': 'Behavioral DNA validator not found (skipped)',
        }

    try:
        result = subprocess.run(
            ['python3', str(validator_path), str(project_path)],
            capture_output=True,
            text=True,
            timeout=30,
        )

        if result.returncode == 0:
            return {
                'passed': True,
            }
        elif result.returncode == 1:
            return {
                'passed': False,
                'error': 'Behavioral DNA validation failed',
                'suggestion': 'Fix characters.md issues reported by validate_behavioral_dna.py',
                'details': result.stdout[-500:] if result.stdout else None,
            }
        else:
            return {
                'passed': True,  # Don't block on config errors
                'skipped': True,
                'note': f'Behavioral DNA validator returned error code {result.returncode}',
            }

    except subprocess.TimeoutExpired:
        return {
            'passed': True,  # Don't block on timeout
            'skipped': True,
            'note': 'Behavioral DNA validator timed out (skipped)',
        }
    except Exception as e:
        return {
            'passed': True,  # Don't block on unexpected errors
            'skipped': True,
            'note': f'Behavioral DNA validator error: {str(e)}',
        }


def check_is_promoted_project(project_path):
    """Verify this is a promoted project (has bible/ folder), not a development project."""
    bible_path = project_path / "bible"

    if not bible_path.exists():
        # Check if this might be a development project
        dev_indicators = ['STATUS.md', 'thematic_spine.md', 'characters.md']
        is_dev = any((project_path / f).exists() for f in dev_indicators)

        if is_dev:
            return {
                'passed': False,
                'error': 'This appears to be a development project, not a promoted project',
                'suggestion': 'Run /promote [project] to create the scripting folder structure',
            }
        else:
            return {
                'passed': False,
                'error': 'No bible/ folder found - project has not been promoted',
                'suggestion': 'Run /promote [project] to create the scripting folder structure',
            }

    return {
        'passed': True,
    }


def main():
    if len(sys.argv) < 2:
        print("Usage: python3 validate_pre_treatment.py <project_path>")
        print("Example: python3 validate_pre_treatment.py ./leviathan")
        sys.exit(2)

    project_path = Path(sys.argv[1]).resolve()

    if not project_path.exists():
        print(f"Error: Project path does not exist: {project_path}")
        sys.exit(2)

    print(f"\n{'='*60}")
    print(f"PRE-TREATMENT GATE: {project_path.name}")
    print(f"{'='*60}")

    all_passed = True
    results = {}

    # Check 1: Is this a promoted project?
    print(f"\nChecking project structure...")
    results['promoted'] = check_is_promoted_project(project_path)
    if not results['promoted']['passed']:
        print(f"  ERROR: {results['promoted']['error']}")
        print(f"  -> {results['promoted']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: Project has bible/ folder structure")

    if not all_passed:
        # Can't continue if not a promoted project
        print(f"\n{'='*60}")
        print(f"PRE-TREATMENT GATE: FAILED")
        print(f"\nCANNOT PROCEED TO TREATMENT GENERATION")
        print(f"\nThis project must be promoted first:")
        print(f"  1. Complete 34/34 checklist in /projects/{project_path.name}/development/")
        print(f"  2. Run /validate {project_path.name}")
        print(f"  3. Run /promote {project_path.name}")
        print(f"{'='*60}\n")
        sys.exit(1)

    # Check 2: [FILL] placeholders (must be completed before treatment)
    print(f"\nChecking for [FILL] placeholders in bible docs...")
    results['fill_placeholders'] = check_fill_placeholders(project_path)
    if results['fill_placeholders'].get('skipped'):
        print(f"  SKIPPED: No bible/ folder")
    elif not results['fill_placeholders']['passed']:
        print(f"  ERROR: {results['fill_placeholders']['error']}")
        print(f"  -> {results['fill_placeholders']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: No [FILL] placeholders remaining")

    # Check 3: episode_arc.md
    print(f"\nChecking bible/episode_arc.md...")
    results['episode_arc'] = check_episode_arc(project_path)
    if not results['episode_arc']['passed']:
        print(f"  ERROR: {results['episode_arc']['error']}")
        if 'missing' in results['episode_arc']:
            print(f"  Missing episodes: {results['episode_arc']['missing']}")
        print(f"  -> {results['episode_arc']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: {results['episode_arc']['episode_count']} episodes defined")

    # Check 3: characters.md
    print(f"\nChecking bible/characters.md...")
    results['characters'] = check_characters(project_path)
    if not results['characters']['passed']:
        print(f"  ERROR: {results['characters']['error']}")
        print(f"  -> {results['characters']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: {results['characters']['character_count']} characters defined")

    # Check 4: series_bible.md
    print(f"\nChecking bible/series_bible.md...")
    results['series_bible'] = check_series_bible(project_path)
    if not results['series_bible']['passed']:
        print(f"  ERROR: {results['series_bible']['error']}")
        print(f"  -> {results['series_bible']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: {results['series_bible']['word_count']} words")

    # Check 5: state folder
    print(f"\nChecking state/current_state.json...")
    results['state'] = check_state_folder(project_path)
    if not results['state']['passed']:
        print(f"  ERROR: {results['state']['error']}")
        print(f"  -> {results['state']['suggestion']}")
        all_passed = False
    else:
        print(f"  OK: State tracking initialized")

    # Check 6: Behavioral DNA validation (soft - reports but doesn't block)
    print(f"\nRunning behavioral DNA validation...")
    results['behavioral_dna'] = run_behavioral_dna_validation(project_path)
    if results['behavioral_dna'].get('skipped'):
        print(f"  SKIPPED: {results['behavioral_dna']['note']}")
    elif not results['behavioral_dna']['passed']:
        print(f"  WARNING: {results['behavioral_dna']['error']}")
        print(f"  -> {results['behavioral_dna']['suggestion']}")
        # Make this a hard gate by uncommenting:
        all_passed = False
    else:
        print(f"  OK: Character behavioral DNA validated")

    # Final result
    print(f"\n{'='*60}")

    if all_passed:
        print(f"PRE-TREATMENT GATE: PASSED")
        print(f"\nAll prerequisites met. Treatment generation may proceed.")
        print(f"\nNext step:")
        print(f"  /treatment {project_path.name}")
        print(f"{'='*60}\n")
        sys.exit(0)
    else:
        print(f"PRE-TREATMENT GATE: FAILED")
        print(f"\nCANNOT PROCEED TO TREATMENT GENERATION")
        print(f"\nFix the issues above, then re-run:")
        print(f"  python3 .claude/hooks/validate_pre_treatment.py {project_path}")
        print(f"{'='*60}\n")
        sys.exit(1)


if __name__ == "__main__":
    main()
