#!/usr/bin/env python3
"""
souleyez.parsers.hashcat_parser

Parse hashcat output and extract cracked passwords.
"""
import re
from typing import Dict, Any, List


def parse_hashcat_output(output: str, hash_file: str = "") -> Dict[str, Any]:
    """
    Parse hashcat output and extract cracked passwords.
    
    Hashcat output format:
        <hash>:<password>
        
    Args:
        output: Raw hashcat output text
        hash_file: Path to hash file (for reference)
        
    Returns:
        Dict with structure:
        {
            'hash_file': str,
            'cracked': [
                {
                    'hash': str,
                    'password': str,
                    'hash_type': str  # if identifiable
                }
            ],
            'stats': {
                'cracked_count': int,
                'status': str  # 'cracked', 'exhausted', 'running'
            }
        }
    """
    result = {
        'hash_file': hash_file,
        'cracked': [],
        'stats': {
            'cracked_count': 0,
            'status': 'unknown'
        }
    }
    
    lines = output.split('\n')
    
    for line in lines:
        line_stripped = line.strip()
        
        # Parse cracked hash:password pairs
        # Format varies but typically: hash:password
        if ':' in line_stripped and not line_stripped.startswith('#'):
            # Skip status lines
            if any(x in line_stripped.lower() for x in ['status', 'progress', 'speed', 'recovered']):
                continue
                
            parts = line_stripped.split(':', 1)
            if len(parts) == 2:
                hash_value = parts[0].strip()
                password = parts[1].strip()
                
                # Basic validation - hashes are typically hex or base64
                if len(hash_value) >= 16 and password:  # Minimum hash length
                    result['cracked'].append({
                        'hash': hash_value,
                        'password': password,
                        'hash_type': 'unknown'  # Could be determined from -m flag
                    })
        
        # Parse status information
        if 'Status.........:' in line_stripped:
            if 'Cracked' in line_stripped:
                result['stats']['status'] = 'cracked'
            elif 'Exhausted' in line_stripped:
                result['stats']['status'] = 'exhausted'
            elif 'Running' in line_stripped:
                result['stats']['status'] = 'running'
        
        # Parse recovered count
        recovered_match = re.search(r'Recovered[.\s]+:\s+(\d+)/(\d+)', line_stripped)
        if recovered_match:
            result['stats']['cracked_count'] = int(recovered_match.group(1))
            result['stats']['total_count'] = int(recovered_match.group(2))
    
    # Update count from actual cracked list if not found in stats
    if result['stats']['cracked_count'] == 0 and result['cracked']:
        result['stats']['cracked_count'] = len(result['cracked'])
    
    return result


def parse_hashcat_potfile(potfile_path: str) -> List[Dict[str, str]]:
    """
    Parse hashcat potfile (hashcat.potfile) for cracked passwords.
    
    The potfile contains all previously cracked hashes in format:
        hash:password
        
    Args:
        potfile_path: Path to hashcat.potfile
        
    Returns:
        List of dicts with hash and password
    """
    cracked = []
    
    try:
        with open(potfile_path, 'r', encoding='utf-8', errors='replace') as f:
            for line in f:
                line = line.strip()
                if ':' in line:
                    parts = line.split(':', 1)
                    if len(parts) == 2:
                        cracked.append({
                            'hash': parts[0],
                            'password': parts[1]
                        })
    except Exception:
        pass
    
    return cracked


def map_to_credentials(parsed_data: Dict[str, Any], engagement_id: int, host_id: int = None) -> List[Dict[str, Any]]:
    """
    Convert parsed hashcat data into credential records for database storage.
    
    Args:
        parsed_data: Output from parse_hashcat_output()
        engagement_id: Current engagement ID
        host_id: Optional host ID if known
        
    Returns:
        List of credential dicts ready for CredentialManager.add()
    """
    credentials = []
    
    for cracked in parsed_data.get('cracked', []):
        credential = {
            'password': cracked['password'],
            'credential_type': 'password',
            'source': 'hashcat',
            'validation_status': 'cracked',
            'notes': f"Cracked from hash: {cracked['hash'][:32]}...",
            'hash_original': cracked['hash']
        }
        
        if host_id:
            credential['host_id'] = host_id
        
        credentials.append(credential)
    
    return credentials


__all__ = ['parse_hashcat_output', 'parse_hashcat_potfile', 'map_to_credentials']
