"""History management service."""

import json
import os
from datetime import datetime
from pathlib import Path
from typing import List, Optional
from ..config import get_config_dir


def get_history_file() -> Path:
    """Get the history file path."""
    return get_config_dir() / "history.json"


def load_history() -> List[dict]:
    """Load history from file."""
    history_file = get_history_file()
    if not history_file.exists():
        return []

    try:
        with open(history_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    except (json.JSONDecodeError, Exception):
        return []


def save_history(history: List[dict]) -> None:
    """Save history to file."""
    history_file = get_history_file()
    with open(history_file, 'w', encoding='utf-8') as f:
        json.dump(history, f, indent=2, ensure_ascii=False)


def add_to_history(
    id: str,
    title: str,
    url: str,
    file_path: str,
    duration: Optional[str] = None,
    thumbnail: Optional[str] = None,
    initial_cost: Optional[dict] = None,
    language: Optional[str] = None,
    text_direction: Optional[str] = None
) -> dict:
    """Add a new item to history."""
    history = load_history()

    item = {
        'id': id,
        'title': title,
        'url': url,
        'file_path': file_path,
        'created_at': datetime.now().isoformat(),
        'duration': duration,
        'thumbnail': thumbnail,
        'language': language,
        'text_direction': text_direction or 'ltr',
        'analysis': None,  # Will store analysis results
        'translations': {},  # Will store translations by language
        'qa_history': [],  # Q&A exchanges
        'resources': None,  # Saved resources/citations
        'costs': {
            'entries': [],
            'total_cost': 0.0
        }
    }

    # Add initial cost if provided (e.g., transcription cost)
    if initial_cost:
        item['costs']['entries'].append(initial_cost)
        item['costs']['total_cost'] = initial_cost.get('cost_usd', 0)

    # Add to beginning of list
    history.insert(0, item)

    # Keep only last 100 items
    history = history[:100]

    save_history(history)
    return item


def update_history_item(id: str, **kwargs) -> Optional[dict]:
    """Update a history item with new data."""
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == id:
            item.update(kwargs)
            history[i] = item
            save_history(history)
            return item
    return None


def get_history(search: Optional[str] = None, limit: int = 50, offset: int = 0) -> tuple:
    """
    Get history items with optional search.
    Searches in title and transcription text content.

    Returns (items, total_count)
    """
    history = load_history()

    if search:
        search_lower = search.lower()
        filtered = []
        for item in history:
            # Search in title
            if search_lower in item.get('title', '').lower():
                filtered.append(item)
                continue
            # Search in transcription text
            file_path = item.get('file_path')
            if file_path:
                text = get_transcription_text(file_path)
                if text and search_lower in text.lower():
                    filtered.append(item)
        history = filtered

    total = len(history)
    items = history[offset:offset + limit]

    return items, total


def get_history_item(id: str) -> Optional[dict]:
    """Get a specific history item by ID."""
    history = load_history()
    for item in history:
        if item.get('id') == id:
            return item
    return None


def delete_history_item(id: str) -> bool:
    """Delete a history item by ID."""
    history = load_history()
    original_len = len(history)

    history = [item for item in history if item.get('id') != id]

    if len(history) < original_len:
        save_history(history)
        return True
    return False


def clear_history() -> None:
    """Clear all history."""
    save_history([])


def get_transcription_text(file_path: str) -> Optional[str]:
    """Read transcription text from file."""
    try:
        if os.path.exists(file_path):
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                # Skip header if present
                if content.startswith('Title:'):
                    lines = content.split('\n')
                    # Find the separator line and skip past it
                    for i, line in enumerate(lines):
                        if line.startswith('==='):
                            return '\n'.join(lines[i+2:]).strip()
                return content
    except Exception:
        pass
    return None


def add_cost_entry(item_id: str, cost_entry: dict) -> Optional[dict]:
    """
    Add a cost entry to an item and update total.

    Args:
        item_id: The history item ID
        cost_entry: Cost entry dict with operation, provider, model, cost_usd, timestamp

    Returns:
        Updated item or None if not found
    """
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == item_id:
            # Ensure costs structure exists
            if 'costs' not in item:
                item['costs'] = {'entries': [], 'total_cost': 0.0}

            # Add entry
            item['costs']['entries'].append(cost_entry)
            item['costs']['total_cost'] += cost_entry.get('cost_usd', 0)
            item['costs']['total_cost'] = round(item['costs']['total_cost'], 6)

            history[i] = item
            save_history(history)
            return item

    return None


def add_qa_entry(item_id: str, question: str, answer: str, cost_info: dict = None, references: dict = None) -> Optional[dict]:
    """
    Add a Q&A exchange to an item's history.

    Args:
        item_id: The history item ID
        question: The question asked
        answer: The answer received
        cost_info: Optional cost info for this Q&A
        references: Optional references/citations

    Returns:
        Updated item or None if not found
    """
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == item_id:
            # Ensure qa_history exists
            if 'qa_history' not in item:
                item['qa_history'] = []

            qa_entry = {
                'question': question,
                'answer': answer,
                'timestamp': datetime.now().isoformat()
            }

            if cost_info:
                qa_entry['cost_info'] = cost_info
            if references:
                qa_entry['references'] = references

            item['qa_history'].append(qa_entry)

            # Also add cost to costs if provided
            if cost_info:
                if 'costs' not in item:
                    item['costs'] = {'entries': [], 'total_cost': 0.0}
                cost_entry = {**cost_info, 'operation': 'qa'}
                item['costs']['entries'].append(cost_entry)
                item['costs']['total_cost'] += cost_entry.get('cost_usd', 0)
                item['costs']['total_cost'] = round(item['costs']['total_cost'], 6)

            history[i] = item
            save_history(history)
            return item

    return None


def save_resources(item_id: str, resources: dict, cost_info: dict = None) -> Optional[dict]:
    """
    Save resources/citations to an item.

    Args:
        item_id: The history item ID
        resources: Resources dict with answer, citations, etc.
        cost_info: Optional cost info for this request

    Returns:
        Updated item or None if not found
    """
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == item_id:
            item['resources'] = resources

            # Add cost if provided
            if cost_info:
                if 'costs' not in item:
                    item['costs'] = {'entries': [], 'total_cost': 0.0}
                cost_entry = {**cost_info, 'operation': 'resources'}
                item['costs']['entries'].append(cost_entry)
                item['costs']['total_cost'] += cost_entry.get('cost_usd', 0)
                item['costs']['total_cost'] = round(item['costs']['total_cost'], 6)

            history[i] = item
            save_history(history)
            return item

    return None


def get_item_costs(item_id: str) -> dict:
    """Get all costs for an item."""
    item = get_history_item(item_id)
    if not item:
        return {'entries': [], 'total_cost': 0.0}
    return item.get('costs', {'entries': [], 'total_cost': 0.0})


def _migrate_analysis_format(item: dict) -> dict:
    """
    Migrate old single-analysis format to per-provider format.
    Called when loading items to ensure backwards compatibility.
    """
    analysis = item.get('analysis')
    if analysis is None:
        return item

    # Check if already in new format (dict with 'analyses' key)
    if isinstance(analysis, dict) and 'analyses' in analysis:
        return item

    # Old format: analysis is either a string or a dict with content
    # Convert to new format
    timestamp = item.get('analyzed_at', item.get('created_at', datetime.now().isoformat()))

    if isinstance(analysis, str):
        # Very old format: just a string
        new_analysis = {
            'analyses': {
                'unknown': {
                    'content': {'analysis': analysis},
                    'provider': 'unknown',
                    'timestamp': timestamp
                }
            },
            'primary_provider': 'unknown'
        }
    elif isinstance(analysis, dict):
        # Current format: dict with analysis, topics, provider, etc.
        provider = analysis.get('provider', 'unknown')
        new_analysis = {
            'analyses': {
                provider: {
                    'content': analysis,
                    'provider': provider,
                    'timestamp': timestamp,
                    'cost_info': analysis.get('cost_info')
                }
            },
            'primary_provider': provider
        }
    else:
        return item

    item['analysis'] = new_analysis
    return item


def save_provider_analysis(
    item_id: str,
    provider: str,
    analysis_content: dict,
    cost_info: dict = None,
    set_as_primary: bool = True
) -> Optional[dict]:
    """
    Save an analysis from a specific provider.

    Args:
        item_id: The history item ID
        provider: Provider name (openai, anthropic, google, etc.)
        analysis_content: The analysis result dict
        cost_info: Optional cost information
        set_as_primary: Whether to set this as the primary/default analysis

    Returns:
        Updated item or None if not found
    """
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == item_id:
            # Ensure analysis structure exists
            if 'analysis' not in item or item['analysis'] is None:
                item['analysis'] = {'analyses': {}, 'primary_provider': None}

            # Migrate old format if needed
            item = _migrate_analysis_format(item)

            # Add this provider's analysis
            item['analysis']['analyses'][provider] = {
                'content': analysis_content,
                'provider': provider,
                'timestamp': datetime.now().isoformat(),
                'cost_info': cost_info
            }

            # Set as primary if requested or if it's the first analysis
            if set_as_primary or not item['analysis'].get('primary_provider'):
                item['analysis']['primary_provider'] = provider

            history[i] = item
            save_history(history)
            return item

    return None


def get_analysis_for_provider(item_id: str, provider: str) -> Optional[dict]:
    """
    Get analysis from a specific provider.

    Args:
        item_id: The history item ID
        provider: Provider name

    Returns:
        Provider's analysis dict or None
    """
    item = get_history_item(item_id)
    if not item:
        return None

    item = _migrate_analysis_format(item)
    analysis = item.get('analysis')
    if not analysis or 'analyses' not in analysis:
        return None

    return analysis['analyses'].get(provider)


def get_all_analyses(item_id: str) -> dict:
    """
    Get all provider analyses for an item.

    Args:
        item_id: The history item ID

    Returns:
        Dict with 'analyses' (by provider) and 'primary_provider'
    """
    item = get_history_item(item_id)
    if not item:
        return {'analyses': {}, 'primary_provider': None}

    item = _migrate_analysis_format(item)
    analysis = item.get('analysis')
    if not analysis or 'analyses' not in analysis:
        return {'analyses': {}, 'primary_provider': None}

    return {
        'analyses': analysis.get('analyses', {}),
        'primary_provider': analysis.get('primary_provider')
    }


def set_primary_analysis_provider(item_id: str, provider: str) -> Optional[dict]:
    """
    Set which provider's analysis should be shown by default.

    Args:
        item_id: The history item ID
        provider: Provider name to set as primary

    Returns:
        Updated item or None if not found
    """
    history = load_history()

    for i, item in enumerate(history):
        if item.get('id') == item_id:
            item = _migrate_analysis_format(item)
            analysis = item.get('analysis')
            if not analysis or 'analyses' not in analysis:
                return None

            # Check that this provider has an analysis
            if provider not in analysis['analyses']:
                return None

            item['analysis']['primary_provider'] = provider
            history[i] = item
            save_history(history)
            return item

    return None


def get_primary_analysis(item_id: str) -> Optional[dict]:
    """
    Get the primary (default) analysis for an item.

    Args:
        item_id: The history item ID

    Returns:
        Primary analysis content or None
    """
    item = get_history_item(item_id)
    if not item:
        return None

    item = _migrate_analysis_format(item)
    analysis = item.get('analysis')
    if not analysis or 'analyses' not in analysis:
        return None

    primary = analysis.get('primary_provider')
    if primary and primary in analysis['analyses']:
        provider_analysis = analysis['analyses'][primary]
        return provider_analysis.get('content')

    # Fallback to first analysis if no primary set
    if analysis['analyses']:
        first_provider = next(iter(analysis['analyses']))
        return analysis['analyses'][first_provider].get('content')

    return None


def get_full_item(item_id: str) -> Optional[dict]:
    """
    Get complete item data including transcription text, all analysis, Q&A history, resources, and costs.

    Args:
        item_id: The history item ID

    Returns:
        Full item dict or None if not found
    """
    from .language import detect_language_from_text

    item = get_history_item(item_id)
    if not item:
        return None

    # Migrate analysis format if needed
    item = _migrate_analysis_format(item)

    # Get transcription text
    text = get_transcription_text(item.get('file_path', ''))

    # Detect language if not already set
    language = item.get('language')
    text_direction = item.get('text_direction')

    if text and not text_direction:
        detected_lang, detected_dir = detect_language_from_text(text)
        if not language:
            language = detected_lang
        text_direction = detected_dir

        # Update the item in history if we detected language
        if detected_lang or detected_dir:
            update_history_item(item_id, language=language, text_direction=text_direction)

    # Get primary analysis content for backwards compatibility
    analysis_data = item.get('analysis')
    primary_analysis = None
    if analysis_data and 'analyses' in analysis_data:
        primary_provider = analysis_data.get('primary_provider')
        if primary_provider and primary_provider in analysis_data['analyses']:
            primary_analysis = analysis_data['analyses'][primary_provider].get('content')
        elif analysis_data['analyses']:
            # Fallback to first
            first_provider = next(iter(analysis_data['analyses']))
            primary_analysis = analysis_data['analyses'][first_provider].get('content')

    # Ensure all fields exist with defaults
    return {
        **item,
        'transcription': text,
        'language': language,
        'text_direction': text_direction or 'ltr',
        'qa_history': item.get('qa_history', []),
        'resources': item.get('resources'),
        'costs': item.get('costs', {'entries': [], 'total_cost': 0.0}),
        'analysis': primary_analysis,  # Primary analysis content for backwards compat
        'all_analyses': analysis_data,  # Full analysis collection
        'translations': item.get('translations', {})
    }


# =============================================================================
# v3 Project Migration Functions
# =============================================================================

def migrate_history_to_projects() -> dict:
    """
    Migrate all history items to the v3 project format.

    Returns:
        Dict with migration statistics
    """
    from .project import (
        load_projects, save_projects, migrate_history_item_to_project
    )

    history = load_history()
    existing_projects = load_projects()
    existing_ids = {p.get('video_id') for p in existing_projects}

    migrated = 0
    skipped = 0
    errors = 0

    for item in history:
        item_id = item.get('id')

        # Skip if already migrated
        if item_id in existing_ids:
            skipped += 1
            continue

        try:
            # Get transcription text
            text = get_transcription_text(item.get('file_path', ''))

            # Migrate to project format
            project = migrate_history_item_to_project(item, text or '')

            # Add to projects list
            existing_projects.insert(0, project.to_dict())
            existing_ids.add(item_id)
            migrated += 1
        except Exception as e:
            errors += 1

    # Save migrated projects
    if migrated > 0:
        save_projects(existing_projects)

    return {
        'total_history_items': len(history),
        'migrated': migrated,
        'skipped': skipped,
        'errors': errors
    }


def get_or_create_project(item_id: str) -> Optional[dict]:
    """
    Get a project for a history item, creating it if it doesn't exist.

    This provides backward compatibility - existing code can still use
    history items, but they'll be auto-converted to projects on access.

    Args:
        item_id: The history item / project ID

    Returns:
        Project dict or None if not found
    """
    from .project import get_project, save_project, migrate_history_item_to_project

    # First check if project already exists
    project = get_project(item_id)
    if project:
        return project.to_dict()

    # Get the history item
    item = get_history_item(item_id)
    if not item:
        return None

    # Migrate it to project format
    text = get_transcription_text(item.get('file_path', ''))
    project = migrate_history_item_to_project(item, text or '')

    # Save and return
    save_project(project)
    return project.to_dict()


def sync_history_item_to_project(item_id: str) -> Optional[dict]:
    """
    Sync changes from history item to its corresponding project.

    Call this after updating a history item to keep the project in sync.

    Args:
        item_id: The history item ID

    Returns:
        Updated project dict or None
    """
    from .project import get_project, save_project

    item = get_history_item(item_id)
    if not item:
        return None

    project = get_project(item_id)
    if not project:
        # Create new project
        return get_or_create_project(item_id)

    # Sync relevant fields from history to project
    text = get_transcription_text(item.get('file_path', ''))

    project.title = item.get('title', project.title)
    project.url = item.get('url', project.url)
    project.thumbnail = item.get('thumbnail', project.thumbnail)
    project.file_path = item.get('file_path', project.file_path)
    project.language = item.get('language', project.language)
    project.text_direction = item.get('text_direction', project.text_direction)
    project.transcription = text or project.transcription
    project.qa_history = item.get('qa_history', project.qa_history)
    project.resources = item.get('resources', project.resources)
    project.costs = item.get('costs', project.costs)

    # Sync analysis
    analysis_data = item.get('analysis')
    if analysis_data and isinstance(analysis_data, dict) and 'analyses' in analysis_data:
        project.analyses = analysis_data.get('analyses', {})
        project.primary_analysis_provider = analysis_data.get('primary_provider')

    save_project(project)
    return project.to_dict()
