"""
Resume Facade Library

A clean Python facade over third-party resume tools:
- Uses jsonresume-to-rendercv for JSON Resume <-> renderCV conversion
- Uses rendercv API for rendering resumes to various formats

Installation:
    pip install jsonresume-to-rendercv rendercv[full] pydantic

Usage:
    from resume_facade import resumejson_to_rendercv, rendercv_to_resumejson, render_resume_w_rendercv

    # Convert between formats
    rendercv_dict = resumejson_to_rendercv(resumejson_dict)
    resumejson_dict = rendercv_to_resumejson(rendercv_dict)

    # Render resume to various formats
    pdf_bytes = render_resume_w_rendercv(rendercv_dict, 'pdf', theme='classic')
    html_bytes = render_resume_w_rendercv(rendercv_dict, 'html')
"""

import io
import json
import tempfile
import subprocess
import yaml
from pathlib import Path
from typing import Dict, Any, Optional, Union, Literal
import logging
import urllib.parse

try:
    # Try to import the third-party packages
    import rendercv.api
    import rendercv.data

    RENDERCV_AVAILABLE = True
except ImportError:
    RENDERCV_AVAILABLE = False
    rendercv = None

# For the conversion tool, we'll use subprocess since it's primarily a CLI tool
JSONRESUME_TO_RENDERCV_AVAILABLE = True  # We'll check this at runtime


def _check_dependencies():
    """Check if required dependencies are available."""
    missing = []

    if not RENDERCV_AVAILABLE:
        missing.append("rendercv[full] - pip install 'rendercv[full]'")

    # Check if jsonresume-to-rendercv CLI is available
    try:
        # This tool doesn't support --help, so we just check if it runs without args
        result = subprocess.run(
            ['jsonresume_to_rendercv'], capture_output=True, check=False
        )
        # If it runs (even with error code 1 for missing args), it's available
        # FileNotFoundError would be raised if the command doesn't exist
    except FileNotFoundError:
        missing.append("jsonresume-to-rendercv - pip install jsonresume-to-rendercv")

    if missing:
        raise ImportError(f"Missing dependencies: {', '.join(missing)}")


def _normalize_resumejson(resumejson_dict: dict[str, Any]) -> dict[str, Any]:
    """
    Normalize JSON Resume data to ensure all required fields are present.

    The jsonresume-to-rendercv tool is strict about required fields, so we'll
    add missing fields with appropriate defaults to make the conversion robust.

    Args:
        resumejson_dict: Original resume data

    Returns:
        Normalized resume data with all required fields
    """
    import copy
    from collections import defaultdict

    # Create a deep copy to avoid modifying the original
    normalized = copy.deepcopy(resumejson_dict)

    # Define required fields for each section with their default values
    SECTION_DEFAULTS = {
        'basics': {
            'name': '',
            'label': '',
            'email': '',
            'phone': '',
            'url': '',
            'summary': '',
            'location': {
                'address': '',
                'postalCode': '',
                'city': '',
                'countryCode': '',
                'region': '',
            },
            'profiles': [],
        },
        'work': {
            '_item_defaults': {
                'name': '',
                'position': '',
                'url': '',
                'startDate': '2000-01',  # Default to a valid date format
                # 'endDate' intentionally omitted - empty string fails validation
                'summary': '',
                'highlights': [],
                'location': '',
            }
        },
        'volunteer': {
            '_item_defaults': {
                'organization': '',
                'position': '',
                'url': '',
                'startDate': '2000-01',
                # 'endDate' intentionally omitted - empty string fails validation
                'summary': '',
                'highlights': [],
            }
        },
        'education': {
            '_item_defaults': {
                'institution': '',
                'url': '',
                'area': '',
                'studyType': '',
                'startDate': '2000-01',  # Required by jsonresume-to-rendercv
                # 'endDate' intentionally omitted - empty string fails validation
                'score': '',
                'courses': [],
            }
        },
        'awards': {
            '_item_defaults': {
                'title': '',
                'date': '2000-01',
                'awarder': '',
                'summary': '',
            }
        },
        'certificates': {
            '_item_defaults': {'name': '', 'date': '2000-01', 'issuer': '', 'url': ''}
        },
        'publications': {
            '_item_defaults': {
                'name': '',
                'publisher': '',
                'releaseDate': '2000-01',  # Required by jsonresume-to-rendercv
                'url': '',
                'summary': '',
            }
        },
        'skills': {'_item_defaults': {'name': '', 'level': '', 'keywords': []}},
        'languages': {'_item_defaults': {'language': '', 'fluency': ''}},
        'interests': {'_item_defaults': {'name': '', 'keywords': []}},
        'references': {'_item_defaults': {'name': '', 'reference': ''}},
        'projects': {
            '_item_defaults': {
                'name': '',
                'description': '',
                'highlights': [],
                'keywords': [],
                'startDate': '2000-01',
                # 'endDate' intentionally omitted - empty string fails validation
                'url': '',
                'roles': [],
                'entity': '',
                'type': '',
            }
        },
    }

    # Normalize top-level sections
    for section_name, defaults in SECTION_DEFAULTS.items():
        if section_name not in normalized:
            if '_item_defaults' in defaults:
                normalized[section_name] = []
            else:
                normalized[section_name] = {}

        section_data = normalized[section_name]

        if '_item_defaults' in defaults:
            # This is an array section (work, education, etc.)
            item_defaults = defaults['_item_defaults']
            if isinstance(section_data, list):
                for item in section_data:
                    if isinstance(item, dict):
                        # First, remove empty date fields that would fail validation
                        date_fields = ['endDate', 'date']
                        for date_field in date_fields:
                            if date_field in item and item[date_field] == '':
                                del item[date_field]

                        # Then add missing required fields
                        for key, default_value in item_defaults.items():
                            if key not in item:
                                item[key] = default_value
        else:
            # This is an object section (basics)
            if isinstance(section_data, dict):
                for key, default_value in defaults.items():
                    if key not in section_data:
                        section_data[key] = default_value

    return normalized


def sanitize_rendercv_data(data: dict[str, Any]) -> dict[str, Any]:
    """
    Sanitize a renderCV-like dict (or JSON Resume normalized dict) so that
    - empty-string values are removed to avoid jsonschema minLength failures,
    - URLs containing '@' are preserved as visible text in a 'journal' field
      while reducing the clickable 'url' to an origin-only target to avoid
      Typst label tokenization problems.

    This function is intentionally conservative: it removes only empty strings
    and rewrites urls that contain '@'. It returns a deep-copied sanitized
    structure.
    """
    from typing import Any
    import copy

    def _clean(obj: Any) -> Any:
        if isinstance(obj, dict):
            out: dict[str, Any] = {}
            for k, v in obj.items():
                if v == "":
                    continue
                cleaned = _clean(v)
                out[k] = cleaned
            return out
        elif isinstance(obj, list):
            out_list = []
            for item in obj:
                if item == "":
                    continue
                cleaned_item = _clean(item)
                out_list.append(cleaned_item)
            return out_list
        else:
            return obj

    cleaned = copy.deepcopy(data)

    url_sections = [
        'work',
        'volunteer',
        'education',
        'publications',
        'projects',
        'certificates',
        'awards',
    ]

    for section in url_sections:
        items = cleaned.get(section)
        if isinstance(items, list):
            for item in items:
                if isinstance(item, dict) and item.get('url'):
                    url_val = item.get('url')
                    if isinstance(url_val, str) and '@' in url_val:
                        original = url_val
                        parsed = urllib.parse.urlparse(original)
                        origin = None
                        if parsed.scheme and parsed.netloc:
                            origin = f"{parsed.scheme}://{parsed.netloc}/"
                        else:
                            origin = original.split('@')[0]

                        item['journal'] = original
                        item['url'] = origin

    # Some renderCV sections (for example 'technologies') expect a
    # OneLineEntry with a non-empty 'details' field. If the input has
    # empty or missing details we should drop those entries to avoid
    # validation failures during rendering. Support both shapes:
    # - top-level section lists (cleaned['technologies'])
    # - renderCV shape (cleaned['cv']['sections']['technologies'])
    def _prune_empty_one_line_section(container: dict, section_name: str):
        if not isinstance(container, dict):
            return
        items = container.get(section_name)
        if not isinstance(items, list):
            return
        new_items = []
        for it in items:
            if isinstance(it, dict):
                # If 'details' is missing or empty, drop the entry
                if it.get('details', None) in (None, ''):
                    continue
            new_items.append(it)
        container[section_name] = new_items

    _prune_empty_one_line_section(cleaned, 'technologies')
    if isinstance(cleaned.get('cv'), dict) and isinstance(
        cleaned['cv'].get('sections'), dict
    ):
        _prune_empty_one_line_section(cleaned['cv']['sections'], 'technologies')

    # If technologies section is now empty, remove it entirely so RenderCV
    # doesn't attempt to validate an empty section.
    if (
        isinstance(cleaned.get('technologies'), list)
        and len(cleaned['technologies']) == 0
    ):
        del cleaned['technologies']

    if (
        isinstance(cleaned.get('cv'), dict)
        and isinstance(cleaned['cv'].get('sections'), dict)
        and isinstance(cleaned['cv']['sections'].get('technologies'), list)
        and len(cleaned['cv']['sections']['technologies']) == 0
    ):
        del cleaned['cv']['sections']['technologies']

    cleaned = _clean(cleaned)
    logging.getLogger(__name__).debug("sanitize_rendercv_data applied")
    return cleaned


def is_valid_rendercv_dict(d: dict[str, Any], strict: bool = True) -> bool:
    """
    Heuristic validator that returns True when the provided dict looks
    like a renderCV input dict.

    Args:
        d: candidate dictionary
        strict: when True, require presence of 'cv' and at least one of
            'sections' or 'design' with expected shapes. When False, use
            a looser heuristic that allows top-level keys like 'name',
            'sections', or 'cv' to be present.

    Returns:
        True if the dict appears to be renderCV-shaped.
    """
    if not isinstance(d, dict):
        return False

    # Strict mode: must have top-level 'cv' dict with 'sections' (dict)
    if strict:
        cv = d.get('cv')
        if not isinstance(cv, dict):
            return False
        sections = cv.get('sections')
        if not isinstance(sections, dict):
            return False
        # Basic sanity: sections should have at least one key mapping to a list
        for v in sections.values():
            if isinstance(v, list):
                return True
        return False

    # Loose mode: accept many shapes commonly present in renderCV data
    loose_indicators = ('cv', 'sections', 'design', 'name', 'experience', 'education')
    for k in loose_indicators:
        if k in d:
            return True
    return False


def resumejson_to_rendercv(resumejson_dict: dict[str, Any]) -> dict[str, Any]:
    """
    Convert JSON Resume format to renderCV format using jsonresume-to-rendercv.

    Args:
        resumejson_dict: Resume data in JSON Resume format

    Returns:
        Resume data in renderCV format

    Raises:
        ImportError: If required dependencies are not available
        ValueError: If conversion fails
    """
    _check_dependencies()

    # If the caller already passed a renderCV dict (or a dict with a
    # 'design'/'cv'/'sections' top-level key), don't try to run the
    # jsonresume-to-rendercv converter which expects JSON Resume format.
    if isinstance(resumejson_dict, dict) and any(
        k in resumejson_dict for k in ('cv', 'design', 'sections')
    ):
        rendercv_candidate = sanitize_rendercv_data(resumejson_dict)
        if 'design' not in rendercv_candidate:
            rendercv_candidate = dict(rendercv_candidate)
            rendercv_candidate['design'] = {
                'theme': 'classic',
                'page': {'size': 'us-letter'},
                'text': {'font_family': 'Source Sans 3', 'font_size': '10pt'},
            }
        return rendercv_candidate

    # Normalize the input data to ensure all required fields are present
    normalized_data = _normalize_resumejson(resumejson_dict)

    # Use module-level `sanitize_rendercv_data` to clean the normalized input
    # (defined at module scope) before attempting conversion.

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)

        # Sanitize input to avoid validator failures (empty strings, problematic urls)
        sanitized_input = sanitize_rendercv_data(normalized_data)

        # Write JSON Resume to temp file
        json_file = temp_path / "input.json"
        with open(json_file, 'w', encoding='utf-8') as f:
            json.dump(sanitized_input, f, indent=2, ensure_ascii=False)

        # Convert using jsonresume-to-rendercv CLI
        yaml_file = temp_path / "output.yaml"
        result = subprocess.run(
            ['jsonresume_to_rendercv', str(json_file), str(yaml_file)],
            capture_output=True,
            text=True,
        )

        if result.returncode != 0:
            raise ValueError(f"Conversion failed: {result.stderr}")

        # Read the converted YAML
        with open(yaml_file, encoding='utf-8') as f:
            rendercv_dict = yaml.safe_load(f)

        # Ensure the converted rendercv_dict has a sane default design so
        # downstream rendering (render_resume_w_rendercv) does not fail if
        # callers passed a dict without a 'design' section.
        if isinstance(rendercv_dict, dict):
            if 'design' not in rendercv_dict:
                rendercv_dict = dict(rendercv_dict)  # shallow copy
                rendercv_dict['design'] = {
                    'theme': 'classic',
                    'page': {'size': 'us-letter'},
                    'text': {'font_family': 'Source Sans 3', 'font_size': '10pt'},
                }

        # Sanitize the converted structure as well (some fields appear only
        # after conversion and may contain empty strings or problematic urls)
        if isinstance(rendercv_dict, dict):
            rendercv_dict = sanitize_rendercv_data(rendercv_dict)

        return rendercv_dict


def rendercv_to_resumejson(rendercv_dict: dict[str, Any]) -> dict[str, Any]:
    """
    Convert renderCV format to JSON Resume format.

    Note: This is a reverse conversion. Since jsonresume-to-rendercv only goes
    one direction, this implements the reverse mapping.

    Args:
        rendercv_dict: Resume data in renderCV format

    Returns:
        Resume data in JSON Resume format
    """
    # Extract CV data
    cv_data = rendercv_dict.get('cv', {})

    # Build JSON Resume structure
    resumejson = {
        "$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json"
    }

    # Convert basics
    basics = {}
    if cv_data.get('name'):
        basics['name'] = cv_data['name']
    if cv_data.get('label'):
        basics['label'] = cv_data['label']
    if cv_data.get('email'):
        basics['email'] = cv_data['email']
    if cv_data.get('phone'):
        basics['phone'] = cv_data['phone']
    if cv_data.get('website'):
        basics['url'] = cv_data['website']
    if cv_data.get('summary'):
        basics['summary'] = cv_data['summary']

    # Convert location
    if cv_data.get('location'):
        location_str = cv_data['location']
        parts = [part.strip() for part in location_str.split(',')]
        if len(parts) >= 3:
            basics['location'] = {
                'city': parts[0],
                'region': parts[1],
                'countryCode': parts[2],
            }
        elif len(parts) == 2:
            basics['location'] = {'city': parts[0], 'region': parts[1]}
        elif len(parts) == 1:
            basics['location'] = {'city': parts[0]}

    # Convert social networks
    social_networks = cv_data.get('social_networks', [])
    if social_networks:
        basics['profiles'] = []
        for social in social_networks:
            profile = {
                'network': social.get('network', ''),
                'username': social.get('username', ''),
            }
            if social.get('url'):
                profile['url'] = social['url']
            basics['profiles'].append(profile)

    if basics:
        resumejson['basics'] = basics

    # Convert sections
    sections = cv_data.get('sections', {})

    # Convert work experience
    for section_name, entries in sections.items():
        section_lower = section_name.lower()

        if any(
            keyword in section_lower for keyword in ['work', 'experience', 'employment']
        ):
            work_entries = []
            for entry in entries:
                if isinstance(entry, dict):
                    work_entry = {
                        'name': entry.get('company', ''),
                        'position': entry.get('position', ''),
                        'location': entry.get('location', ''),
                        'startDate': entry.get('start_date', ''),
                        'endDate': entry.get('end_date', ''),
                        'summary': entry.get('summary', ''),
                        'highlights': entry.get('highlights', []),
                    }
                    if entry.get('url'):
                        work_entry['url'] = entry['url']
                    # Remove empty values
                    work_entry = {k: v for k, v in work_entry.items() if v}
                    work_entries.append(work_entry)

            if work_entries:
                resumejson['work'] = work_entries

        elif 'education' in section_lower:
            education_entries = []
            for entry in entries:
                if isinstance(entry, dict):
                    edu_entry = {
                        'institution': entry.get('institution', ''),
                        'area': entry.get('area', ''),
                        'studyType': entry.get('degree', ''),
                        'startDate': entry.get('start_date', ''),
                        'endDate': entry.get('end_date', ''),
                    }
                    if entry.get('url'):
                        edu_entry['url'] = entry['url']
                    if entry.get('gpa'):
                        edu_entry['score'] = entry['gpa']
                    # Remove empty values
                    edu_entry = {k: v for k, v in edu_entry.items() if v}
                    education_entries.append(edu_entry)

            if education_entries:
                resumejson['education'] = education_entries

        elif 'skill' in section_lower:
            skills = []
            for entry in entries:
                if isinstance(entry, str):
                    # Parse skill strings like "**Name**: keyword1, keyword2"
                    if '**' in entry and ':' in entry:
                        parts = entry.split(':', 1)
                        name = parts[0].replace('**', '').strip()
                        keywords = [kw.strip() for kw in parts[1].split(',')]
                        skills.append({'name': name, 'keywords': keywords})
                    else:
                        skills.append({'name': entry, 'keywords': []})

            if skills:
                resumejson['skills'] = skills

        elif any(keyword in section_lower for keyword in ['project', 'portfolio']):
            projects = []
            for entry in entries:
                if isinstance(entry, dict):
                    project = {
                        'name': entry.get('name', ''),
                        'description': entry.get('summary', ''),
                        'highlights': entry.get('highlights', []),
                        'startDate': entry.get('start_date', entry.get('date', '')),
                        'endDate': entry.get('end_date', ''),
                    }
                    if entry.get('url'):
                        project['url'] = entry['url']
                    # Remove empty values
                    project = {k: v for k, v in project.items() if v}
                    projects.append(project)

            if projects:
                resumejson['projects'] = projects

        elif 'publication' in section_lower:
            publications = []
            for entry in entries:
                if isinstance(entry, dict):
                    pub = {
                        'name': entry.get('title', ''),
                        'releaseDate': entry.get('date', ''),
                        'summary': entry.get('summary', ''),
                    }
                    if entry.get('journal'):
                        pub['publisher'] = entry['journal']
                    elif entry.get('authors'):
                        if isinstance(entry['authors'], list):
                            pub['publisher'] = ', '.join(entry['authors'])
                        else:
                            pub['publisher'] = entry['authors']
                    if entry.get('url'):
                        pub['url'] = entry['url']
                    # Remove empty values
                    pub = {k: v for k, v in pub.items() if v}
                    publications.append(pub)

            if publications:
                resumejson['publications'] = publications

    return resumejson


def render_resume_w_rendercv(
    rendercv_dict: dict[str, Any],
    format_spec: Literal['pdf', 'html', 'markdown', 'typst', 'png'] = 'pdf',
    theme: str = 'classic',
    font_size: str = '10pt',
    page_size: str = 'letterpaper',
    **kwargs,
) -> bytes:
    """
    Render resume using renderCV to the specified format.

    Args:
        rendercv_dict: Resume data in renderCV format
        format_spec: Output format ('pdf', 'html', 'markdown', 'typst', 'png')
        theme: renderCV theme ('classic', 'sb2nov', 'engineeringresumes', 'moderncv')
        font_size: Font size (e.g., '10pt', '11pt', '12pt')
        page_size: Page size ('letterpaper', 'a4paper', etc.)
        **kwargs: Additional options passed to renderCV

    Returns:
        Rendered resume as bytes

    Raises:
        ImportError: If renderCV is not available
        ValueError: If rendering fails
        NotImplementedError: If format is not supported
    """
    _check_dependencies()

    # Ensure we have design settings
    if 'design' not in rendercv_dict:
        rendercv_dict = dict(rendercv_dict)  # Don't modify original
        rendercv_dict['design'] = {}

    # Update design settings with proper renderCV structure
    design = rendercv_dict['design']

    # Set theme
    if 'theme' not in design:
        design['theme'] = theme

    # Set page settings
    if 'page' not in design:
        design['page'] = {}
    page = design['page']

    # Map page_size to renderCV format
    page_size_mapping = {
        'letterpaper': 'us-letter',
        'us-letter': 'us-letter',
        'a4paper': 'a4',
        'a4': 'a4',
    }
    if 'size' not in page:
        page['size'] = page_size_mapping.get(page_size, 'us-letter')

    # Set text settings
    if 'text' not in design:
        design['text'] = {}
    text = design['text']

    if 'font_size' not in text:
        text['font_size'] = font_size

    # Add any additional kwargs that are valid
    for k, v in kwargs.items():
        if k in ['color', 'disable_page_numbering', 'header_separator']:
            design[k] = v

    with tempfile.TemporaryDirectory() as temp_dir:
        temp_path = Path(temp_dir)
        output_file = None

        try:
            if format_spec == 'pdf':
                # Prefer using the rendercv CLI pipeline which produces a
                # real PDF from the YAML/Typst pipeline. Fall back to the
                # API call if the CLI isn't available or fails.
                yaml_file = temp_path / "resume.yaml"
                with open(yaml_file, 'w', encoding='utf-8') as f:
                    yaml.dump(rendercv_dict, f, default_flow_style=False)

                # Try CLI render first
                result = subprocess.run(
                    [
                        'rendercv',
                        'render',
                        '--output-folder-name',
                        str(temp_path),
                        '--dont-generate-html',
                        '--dont-generate-markdown',
                        str(yaml_file),
                    ],
                    capture_output=True,
                    text=True,
                )

                if result.returncode == 0:
                    # The CLI typically generates a PDF; find it
                    pdf_files = list(temp_path.glob("*.pdf"))
                    if pdf_files:
                        output_file = pdf_files[0]
                    else:
                        # If CLI produced a Typst file, try rendering that to PDF
                        typst_files = list(temp_path.glob("*.typ")) + list(
                            temp_path.glob("*.typst")
                        )
                        if typst_files:
                            # Try rendering the typst file via rendercv CLI
                            tf = typst_files[0]
                            rt = subprocess.run(
                                [
                                    'rendercv',
                                    'render',
                                    '--output-folder-name',
                                    str(temp_path),
                                    str(tf),
                                ],
                                capture_output=True,
                                text=True,
                            )
                            if rt.returncode == 0:
                                pdf_files = list(temp_path.glob("*.pdf"))
                                if pdf_files:
                                    output_file = pdf_files[0]
                        # otherwise we'll let the fallback API try below
                else:
                    # CLI failed; surface stderr for easier debugging.
                    raise ValueError(
                        f"PDF generation failed (CLI stdout: {result.stdout!r}, stderr: {result.stderr!r})"
                    )

            elif format_spec == 'markdown':
                output_file = temp_path / "resume.md"
                try:
                    rendercv.api.create_a_markdown_file_from_a_python_dictionary(
                        rendercv_dict, str(output_file)
                    )
                except Exception as md_error:
                    raise ValueError(f"Markdown generation failed: {md_error}")

            elif format_spec == 'typst':
                output_file = temp_path / "resume.typ"
                try:
                    rendercv.api.create_a_typst_file_from_a_python_dictionary(
                        rendercv_dict, str(output_file)
                    )
                except Exception as typst_error:
                    raise ValueError(f"Typst generation failed: {typst_error}")

            elif format_spec == 'png':
                # Generate PDF first, then PNG via renderCV CLI
                yaml_file = temp_path / "resume.yaml"
                with open(yaml_file, 'w', encoding='utf-8') as f:
                    yaml.dump(rendercv_dict, f, default_flow_style=False)

                result = subprocess.run(
                    [
                        'rendercv',
                        'render',
                        '--output-folder-name',
                        str(temp_path),
                        '--dont-generate-html',
                        '--dont-generate-markdown',
                        str(yaml_file),
                    ],
                    capture_output=True,
                    text=True,
                )

                if result.returncode != 0:
                    raise ValueError(
                        f"PNG generation failed (CLI stdout: {result.stdout!r}, stderr: {result.stderr!r})"
                    )

                # Find the first PNG file
                png_files = list(temp_path.glob("*.png"))
                if png_files:
                    output_file = png_files[0]
                else:
                    raise ValueError("PNG file was not generated")

            else:
                raise NotImplementedError(f"Format '{format_spec}' not supported")

            # Read the generated file
            if output_file and output_file.exists():
                with open(output_file, 'rb') as f:
                    return f.read()
            else:
                raise ValueError(f"Output file was not created: {output_file}")

        except Exception as e:
            if "not found" in str(e).lower():
                raise ImportError(
                    f"renderCV command not found. Install with: pip install 'rendercv[full]'"
                )
            raise


# Convenience functions for common use cases
def render_pdf(rendercv_dict: dict[str, Any], **kwargs) -> bytes:
    """Render resume as PDF."""
    return render_resume_w_rendercv(rendercv_dict, 'pdf', **kwargs)


def render_html(rendercv_dict: dict[str, Any], **kwargs) -> bytes:
    """Render resume as HTML."""
    return render_resume_w_rendercv(rendercv_dict, 'html', **kwargs)


def render_markdown(rendercv_dict: dict[str, Any], **kwargs) -> bytes:
    """Render resume as Markdown."""
    return render_resume_w_rendercv(rendercv_dict, 'markdown', **kwargs)


# Example usage
if __name__ == "__main__":
    # Example JSON Resume data
    sample_resumejson = {
        "basics": {
            "name": "John Doe",
            "label": "Software Engineer",
            "email": "john@example.com",
            "phone": "+1-555-123-4567",
            "url": "https://johndoe.dev",
            "summary": "Experienced software engineer with expertise in Python and web development.",
            "location": {
                "city": "San Francisco",
                "region": "California",
                "countryCode": "US",
            },
            "profiles": [
                {
                    "network": "LinkedIn",
                    "username": "johndoe",
                    "url": "https://linkedin.com/in/johndoe",
                },
                {
                    "network": "GitHub",
                    "username": "johndoe",
                    "url": "https://github.com/johndoe",
                },
            ],
        },
        "work": [
            {
                "name": "Tech Corp",
                "position": "Senior Software Engineer",
                "location": "San Francisco, CA",
                "startDate": "2020-01",
                "summary": "Lead backend development for web applications.",
                "highlights": [
                    "Built scalable APIs serving 1M+ requests/day",
                    "Mentored junior developers",
                    "Improved system performance by 40%",
                ],
            }
        ],
    }

    try:
        print("Converting JSON Resume to renderCV...")
        rendercv_dict = resumejson_to_rendercv(sample_resumejson)
        print("✅ Conversion successful!")

        print("Rendering PDF...")
        pdf_bytes = render_pdf(rendercv_dict)
        print(f"✅ PDF rendered: {len(pdf_bytes)} bytes")

        print("Converting back to JSON Resume...")
        resumejson_restored = rendercv_to_resumejson(rendercv_dict)
        print("✅ Reverse conversion successful!")

        # Save files for inspection
        with open('sample_resume.pdf', 'wb') as f:
            f.write(pdf_bytes)

        with open('rendercv_format.yaml', 'w') as f:
            yaml.dump(rendercv_dict, f, default_flow_style=False)

        with open('restored_jsonresume.json', 'w') as f:
            json.dump(resumejson_restored, f, indent=2)

        print("✅ All operations completed successfully!")
        print(
            "Files saved: sample_resume.pdf, rendercv_format.yaml, restored_jsonresume.json"
        )

    except Exception as e:
        print(f"❌ Error: {e}")
        print(
            "Make sure to install: pip install jsonresume-to-rendercv 'rendercv[full]'"
        )
