#!/usr/bin/env python3
"""
User Flow Validation Script

This script automates basic validation checks for user flows defined in TOML format.
It demonstrates how the structured TOML format enables automated quality assurance.

Usage:
    python validate-flows.py
    python validate-flows.py --flow-file planning/freelancer_flows.toml
    python validate-flows.py --verbose --output report.md

Requirements:
    pip install toml
"""

import os
import sys
import toml
import argparse
from pathlib import Path
from typing import Dict, List, Tuple, Any

class FlowValidator:
    def __init__(self, planning_dir: str = "planning"):
        self.planning_dir = Path(planning_dir)
        self.errors = []
        self.warnings = []
        self.flow_files = [
            "freelancer_flows.toml",
            "developer_flows.toml",
            "api_customer_flows.toml"
        ]
        self.story_files = [
            "freelancer-stories.md",
            "developer-stories.md",
            "api-customer-stories.md"
        ]

    def validate_all_flows(self) -> Tuple[int, int]:
        """Validate all flow files and return (errors, warnings) count."""
        print("🔍 Starting User Flow Validation...")
        print("=" * 50)

        total_errors = 0
        total_warnings = 0

        for flow_file in self.flow_files:
            file_path = self.planning_dir / flow_file
            if file_path.exists():
                print(f"\n📄 Validating {flow_file}...")
                errors, warnings = self.validate_flow_file(file_path)
                total_errors += errors
                total_warnings += warnings
            else:
                self.errors.append(f"Flow file not found: {file_path}")
                total_errors += 1

        self.print_summary(total_errors, total_warnings)
        return total_errors, total_warnings

    def validate_flow_file(self, file_path: Path) -> Tuple[int, int]:
        """Validate a single TOML flow file."""
        try:
            with open(file_path, 'r') as f:
                data = toml.load(f)
        except Exception as e:
            error_msg = f"Failed to parse {file_path}: {e}"
            self.errors.append(error_msg)
            print(f"❌ {error_msg}")
            return 1, 0

        file_errors = 0
        file_warnings = 0
        flow_ids = set()

        # Extract flows from the TOML structure
        flows = self.extract_flows(data)

        for flow_id, flow_data in flows.items():
            errors, warnings = self.validate_single_flow(flow_id, flow_data, file_path)
            file_errors += errors
            file_warnings += warnings

            # Check for duplicate flow IDs
            if flow_id in flow_ids:
                self.errors.append(f"Duplicate flow ID: {flow_id} in {file_path}")
                file_errors += 1
            flow_ids.add(flow_id)

        print(f"   ✅ Flows processed: {len(flows)}")
        print(f"   ⚠️  Warnings: {file_warnings}")
        print(f"   ❌ Errors: {file_errors}")

        return file_errors, file_warnings

    def extract_flows(self, data: Dict) -> Dict[str, Dict]:
        """Extract flow definitions from TOML data."""
        flows = {}

        for key, value in data.items():
            if key.startswith('flow.') and isinstance(value, dict):
                # Extract flow ID from key like "flow.create_new_client"
                flow_id = key.replace('flow.', '')

                # Skip sub-sections like "flow.create_new_client.dependencies"
                if '.' not in flow_id and 'id' in value:
                    flows[flow_id] = value

        return flows

    def validate_single_flow(self, flow_id: str, flow_data: Dict, file_path: Path) -> Tuple[int, int]:
        """Validate a single flow definition."""
        errors = 0
        warnings = 0

        # Required fields validation
        required_fields = ['id', 'name', 'type', 'actor', 'trigger', 'description']
        for field in required_fields:
            if field not in flow_data:
                self.errors.append(f"Flow {flow_id}: Missing required field '{field}' in {file_path}")
                errors += 1

        # Flow type validation
        if 'type' in flow_data and flow_data['type'] not in ['atomic', 'composed']:
            self.errors.append(f"Flow {flow_id}: Invalid type '{flow_data['type']}'. Must be 'atomic' or 'composed'")
            errors += 1

        # User story mapping validation
        if 'user_story' not in flow_data:
            self.errors.append(f"Flow {flow_id}: Missing user_story mapping")
            errors += 1
        else:
            us_errors, us_warnings = self.validate_user_story_mapping(flow_id, flow_data['user_story'])
            errors += us_errors
            warnings += us_warnings

        # Success criteria validation
        if 'success_criteria' not in flow_data:
            self.warnings.append(f"Flow {flow_id}: No success criteria defined")
            warnings += 1
        elif 'primary' not in flow_data['success_criteria']:
            self.errors.append(f"Flow {flow_id}: Missing primary success criteria")
            errors += 1

        # Error handling validation
        if 'error_handling' not in flow_data:
            self.warnings.append(f"Flow {flow_id}: No error handling defined")
            warnings += 1

        # Steps validation for atomic flows
        if flow_data.get('type') == 'atomic':
            if 'steps' not in flow_data:
                self.errors.append(f"Flow {flow_id}: Atomic flow missing steps definition")
                errors += 1
            else:
                step_errors = self.validate_flow_steps(flow_id, flow_data['steps'])
                errors += step_errors

        # Composed steps validation for composed flows
        if flow_data.get('type') == 'composed':
            if 'composed_steps' not in flow_data:
                self.errors.append(f"Flow {flow_id}: Composed flow missing composed_steps definition")
                errors += 1

        # Business rules validation
        if 'business_rules' in flow_data:
            br_warnings = self.validate_business_rules(flow_id, flow_data['business_rules'])
            warnings += br_warnings

        return errors, warnings

    def validate_user_story_mapping(self, flow_id: str, user_story: Dict) -> Tuple[int, int]:
        """Validate user story mapping."""
        errors = 0
        warnings = 0

        required_us_fields = ['story_id', 'story_title', 'story_document']
        for field in required_us_fields:
            if field not in user_story:
                self.errors.append(f"Flow {flow_id}: Missing user_story.{field}")
                errors += 1

        # Validate story document exists
        if 'story_document' in user_story:
            story_doc_path = self.planning_dir / user_story['story_document']
            if not story_doc_path.exists():
                self.errors.append(f"Flow {flow_id}: Referenced story document not found: {user_story['story_document']}")
                errors += 1
            else:
                # Validate story ID exists in document
                story_id = user_story.get('story_id', '')
                if not self.story_id_exists_in_document(story_id, story_doc_path):
                    self.errors.append(f"Flow {flow_id}: Story ID '{story_id}' not found in {user_story['story_document']}")
                    errors += 1

        return errors, warnings

    def story_id_exists_in_document(self, story_id: str, doc_path: Path) -> bool:
        """Check if story ID exists in the story document."""
        try:
            with open(doc_path, 'r') as f:
                content = f.read()
                # Look for patterns like "### Story API001:" or "### Story DEV007:"
                return f"Story {story_id}:" in content
        except Exception:
            return False

    def validate_flow_steps(self, flow_id: str, steps: List[Dict]) -> int:
        """Validate flow steps sequence."""
        errors = 0

        if not steps:
            self.errors.append(f"Flow {flow_id}: Steps array is empty")
            return 1

        # Validate step order
        expected_order = 1
        for step in steps:
            if 'order' not in step:
                self.errors.append(f"Flow {flow_id}: Step missing 'order' field")
                errors += 1
            elif step['order'] != expected_order:
                self.warnings.append(f"Flow {flow_id}: Step order {step['order']} expected {expected_order}")

            # Validate required step fields
            required_step_fields = ['action', 'actor']
            for field in required_step_fields:
                if field not in step:
                    self.errors.append(f"Flow {flow_id}: Step {step.get('order', '?')} missing '{field}'")
                    errors += 1

            expected_order += 1

        return errors

    def validate_business_rules(self, flow_id: str, business_rules: Dict) -> int:
        """Validate business rules structure."""
        warnings = 0

        expected_sections = ['constraints', 'validations', 'permissions']
        for section in expected_sections:
            if section not in business_rules:
                self.warnings.append(f"Flow {flow_id}: Business rules missing '{section}' section")
                warnings += 1

        return warnings

    def print_summary(self, total_errors: int, total_warnings: int):
        """Print validation summary."""
        print("\n" + "=" * 50)
        print("📊 VALIDATION SUMMARY")
        print("=" * 50)

        if total_errors == 0 and total_warnings == 0:
            print("🎉 All flows passed validation!")
        else:
            print(f"⚠️  Total Warnings: {total_warnings}")
            print(f"❌ Total Errors: {total_errors}")

            if total_errors > 0:
                print("\n🚨 ERRORS (Must Fix):")
                for i, error in enumerate(self.errors, 1):
                    print(f"  {i}. {error}")

            if total_warnings > 0:
                print("\n⚠️  WARNINGS (Should Fix):")
                for i, warning in enumerate(self.warnings, 1):
                    print(f"  {i}. {warning}")

        # Validation decision
        print("\n🎯 VALIDATION DECISION:")
        if total_errors == 0:
            if total_warnings == 0:
                print("✅ APPROVED: All flows ready for implementation")
            elif total_warnings <= 5:
                print("✅ CONDITIONAL: Minor warnings present, approved for implementation")
            else:
                print("⚠️  CONDITIONAL: Multiple warnings, review recommended before implementation")
        else:
            print("❌ REJECTED: Errors must be fixed before implementation")

    def generate_report(self, output_file: str):
        """Generate a markdown validation report."""
        with open(output_file, 'w') as f:
            f.write("# User Flow Validation Report\n\n")
            f.write(f"**Generated**: {os.system('date')}\n\n")

            if self.errors:
                f.write("## ❌ Errors\n\n")
                for error in self.errors:
                    f.write(f"- {error}\n")
                f.write("\n")

            if self.warnings:
                f.write("## ⚠️ Warnings\n\n")
                for warning in self.warnings:
                    f.write(f"- {warning}\n")
                f.write("\n")

            f.write("## Summary\n\n")
            f.write(f"- Total Errors: {len(self.errors)}\n")
            f.write(f"- Total Warnings: {len(self.warnings)}\n")

def main():
    parser = argparse.ArgumentParser(description='Validate user flows in TOML format')
    parser.add_argument('--flow-file', help='Validate specific flow file')
    parser.add_argument('--planning-dir', default='planning', help='Planning directory path')
    parser.add_argument('--output', help='Generate report to file')
    parser.add_argument('--verbose', action='store_true', help='Verbose output')

    args = parser.parse_args()

    validator = FlowValidator(args.planning_dir)

    if args.flow_file:
        # Validate single file
        file_path = Path(args.flow_file)
        if file_path.exists():
            errors, warnings = validator.validate_flow_file(file_path)
        else:
            print(f"❌ File not found: {file_path}")
            sys.exit(1)
    else:
        # Validate all flows
        errors, warnings = validator.validate_all_flows()

    if args.output:
        validator.generate_report(args.output)
        print(f"\n📄 Report generated: {args.output}")

    # Exit with error code if validation failed
    sys.exit(1 if errors > 0 else 0)

if __name__ == "__main__":
    main()