#!/usr/bin/env python3
"""
Python Font Exporter
Exports FontDefinition (JSON) to TTF/WOFF using fonttools and fontmake
"""

import json
import sys
import os
from pathlib import Path

try:
    from fontTools.ufoLib import UFOWriter
    from fontTools.pens.pointPen import PointToSegmentPen
    from fontTools.pens.recordingPen import RecordingPen
    import subprocess
except ImportError:
    print("Error: fonttools not installed. Install with: pip install fonttools fontmake")
    sys.exit(1)


class FontExporterPython:
    """Export FontDefinition JSON to TTF/WOFF using fonttools"""
    
    def __init__(self):
        self.temp_dir = Path('/tmp/font-creator')
        self.temp_dir.mkdir(exist_ok=True)
    
    def load_font_definition(self, json_path_or_data):
        """Load font definition from JSON file or string"""
        if isinstance(json_path_or_data, (str, Path)) and os.path.exists(json_path_or_data):
            with open(json_path_or_data, 'r') as f:
                return json.load(f)
        elif isinstance(json_path_or_data, str):
            return json.loads(json_path_or_data)
        else:
            return json_path_or_data
    
    def create_ufo_font(self, font_data, ufo_path):
        """Create a UFO font from font definition"""
        ufo_path = Path(ufo_path)
        if ufo_path.exists():
            import shutil
            shutil.rmtree(ufo_path)

        writer = UFOWriter(str(ufo_path))
        glyphset = writer.getGlyphSet()

        # Set font info using info property
        try:
            # Try newer fonttools API first
            info = writer.info
        except AttributeError:
            # Fall back to getInfo method
            try:
                info = writer.getInfo()
            except (AttributeError, TypeError):
                # Create info if neither method works
                from fontTools.ufoLib.objects.info import Info
                info = Info()

        # Set font metrics and metadata
        info.familyName = font_data.get('familyName', font_data.get('name', 'Unknown'))
        info.styleName = font_data.get('styleName', 'Regular')
        info.unitsPerEm = font_data.get('metrics', {}).get('unitsPerEm', 1000)
        info.ascender = font_data.get('metrics', {}).get('ascender', 800)
        info.descender = font_data.get('metrics', {}).get('descender', -200)

        if font_data.get('metrics', {}).get('xHeight'):
            info.xHeight = font_data['metrics']['xHeight']
        if font_data.get('metrics', {}).get('capHeight'):
            info.capHeight = font_data['metrics']['capHeight']

        # Add metadata
        if font_data.get('metadata', {}).get('copyright'):
            info.copyright = font_data['metadata']['copyright']
        if font_data.get('metadata', {}).get('version'):
            info.versionMajor = 1
            info.versionMinor = 0

        # Write info
        writer.writeInfo(info)

        # Create glyphs
        glyphs = font_data.get('glyphs', {})
        for char, glyph_data in glyphs.items():
            self.create_glyph(glyphset, char, glyph_data)

        # Write UFO
        writer.write()
        return ufo_path
    
    def create_glyph(self, glyphset, char, glyph_data):
        """Create a glyph in the UFO"""
        glyph_name = char if char != ' ' else 'space'
        glyph = glyphset.newGlyph(glyph_name)
        glyph.width = glyph_data.get('width', 600)
        
        # Set Unicode
        unicode_val = glyph_data.get('unicode')
        if unicode_val is not None:
            glyph.unicodes = [unicode_val]
        
        # Create pen for drawing
        pen = glyph.getPen()
        
        # Draw contours
        contours = glyph_data.get('contours', [])
        for contour_data in contours:
            self.draw_contour(pen, contour_data)
    
    def draw_contour(self, pen, contour_data):
        """Draw a contour using the pen"""
        points = contour_data.get('points', [])
        if not points:
            return
        
        # Group points into segments
        i = 0
        while i < len(points):
            point = points[i]
            
            if point.get('onCurve', True):
                # On-curve point
                if i == 0:
                    pen.moveTo((point['x'], point['y']))
                    i += 1
                elif i + 2 < len(points) and not points[i + 1].get('onCurve', True) and not points[i + 2].get('onCurve', True):
                    # Cubic Bézier
                    cp1 = points[i + 1]
                    cp2 = points[i + 2]
                    end = points[i + 3] if i + 3 < len(points) else points[0]
                    pen.curveTo(
                        (cp1['x'], cp1['y']),
                        (cp2['x'], cp2['y']),
                        (end['x'], end['y'])
                    )
                    i += 4
                elif i + 1 < len(points) and not points[i + 1].get('onCurve', True):
                    # Quadratic Bézier (convert to cubic)
                    cp = points[i + 1]
                    end = points[i + 2] if i + 2 < len(points) else points[0]
                    # Convert quadratic to cubic
                    qp = (cp['x'], cp['y'])
                    ep = (end['x'], end['y'])
                    sp = (points[i - 1]['x'], points[i - 1]['y']) if i > 0 else (point['x'], point['y'])
                    cp1 = (sp[0] + 2/3 * (qp[0] - sp[0]), sp[1] + 2/3 * (qp[1] - sp[1]))
                    cp2 = (ep[0] + 2/3 * (qp[0] - ep[0]), ep[1] + 2/3 * (qp[1] - ep[1]))
                    pen.curveTo(cp1, cp2, ep)
                    i += 3
                else:
                    # Line to
                    pen.lineTo((point['x'], point['y']))
                    i += 1
            else:
                # Control point - skip (handled above)
                i += 1
        
        pen.closePath()
    
    def export_to_ttf(self, font_data, output_path):
        """Export font to TTF"""
        ufo_path = self.temp_dir / 'temp_font.ufo'
        self.create_ufo_font(font_data, ufo_path)
        
        # Use fontmake to compile
        result = subprocess.run(
            ['fontmake', '-u', str(ufo_path), '-o', 'ttf', '--output-dir', str(Path(output_path).parent)],
            capture_output=True,
            text=True
        )
        
        if result.returncode != 0:
            raise RuntimeError(f"fontmake failed: {result.stderr}")
        
        # Find generated file
        generated = Path(output_path).parent / f"{ufo_path.stem}.ttf"
        if generated.exists():
            import shutil
            shutil.move(str(generated), str(output_path))
        
        return output_path
    
    def export_to_woff2(self, font_data, output_path):
        """Export font to WOFF2"""
        # First create TTF
        ttf_path = self.temp_dir / 'temp_font.ttf'
        self.export_to_ttf(font_data, ttf_path)
        
        # Convert TTF to WOFF2 using fonttools
        from fontTools.ttLib import TTFont
        
        font = TTFont(str(ttf_path))
        font.flavor = 'woff2'
        font.save(str(output_path))
        
        return output_path
    
    def export(self, font_json_path_or_data, output_path, format='ttf'):
        """Main export function"""
        font_data = self.load_font_definition(font_json_path_or_data)
        
        output_path = Path(output_path)
        
        if format.lower() == 'ttf':
            return self.export_to_ttf(font_data, output_path)
        elif format.lower() == 'woff2':
            return self.export_to_woff2(font_data, output_path)
        else:
            raise ValueError(f"Unsupported format: {format}")


def main():
    """CLI interface"""
    if len(sys.argv) < 3:
        print("Usage: python-exporter.py <input.json> <output.ttf|woff2>")
        sys.exit(1)
    
    input_path = sys.argv[1]
    output_path = sys.argv[2]
    
    format = Path(output_path).suffix[1:].lower()
    if format not in ['ttf', 'woff2']:
        print(f"Error: Output format must be .ttf or .woff2, got .{format}")
        sys.exit(1)
    
    exporter = FontExporterPython()
    try:
        result = exporter.export(input_path, output_path, format)
        print(f"Successfully exported font to {result}")
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == '__main__':
    main()
