//! SwiftUI code generation for Perry widget extensions
//!
//! Compiles WidgetDecl HIR nodes to SwiftUI source code for WidgetKit.
//! Produces Swift files that can be compiled with `swiftc` into a .appex bundle.
//! Supports both iOS and watchOS targets.

mod emit;

use anyhow::Result;
use perry_hir::ir::WidgetDecl;

/// Generated output for a widget extension
pub struct WidgetBundle {
    /// Swift source files: (filename, source_code)
    pub swift_files: Vec<(String, String)>,
    /// Info.plist content
    pub info_plist: String,
    /// Widget extension bundle ID
    pub bundle_id: String,
}

/// Compile a WidgetDecl to a complete WidgetKit extension bundle.
///
/// Generates:
/// - {Name}.swift: Entry struct, SwiftUI View, TimelineProvider, @main entry point
/// - {Name}Glue.swift: Native FFI bridge (if provider_func_name is set)
/// - {Name}Intent.swift: AppIntent configuration (if config_params is non-empty)
/// - Info.plist
pub fn compile_widget(widget: &WidgetDecl, app_bundle_id: &str) -> Result<WidgetBundle> {
    let safe_name = sanitize_kind(&widget.kind);
    let bundle_id = format!("{}.widget", app_bundle_id);

    // Generate the Entry struct (with nested Codable structs for complex types)
    let entry_struct = emit::emit_entry_struct(widget, &safe_name);

    // Generate the SwiftUI View from render body
    let view_body = emit::emit_view(widget, &safe_name);

    // Generate the TimelineProvider
    let provider = emit::emit_timeline_provider(widget, &safe_name);

    // Generate the @main WidgetBundle entry point
    let widget_bundle = emit::emit_widget_bundle(widget, &safe_name);

    // Combine into main Swift file
    let mut swift_source = String::with_capacity(8192);
    swift_source.push_str("// Auto-generated by Perry compiler — do not edit\n");
    swift_source.push_str("import WidgetKit\n");
    swift_source.push_str("import SwiftUI\n");
    if !widget.config_params.is_empty() {
        swift_source.push_str("import AppIntents\n");
    }
    swift_source.push('\n');
    swift_source.push_str(&entry_struct);
    swift_source.push('\n');
    swift_source.push_str(&view_body);
    swift_source.push('\n');
    swift_source.push_str(&provider);
    swift_source.push('\n');
    swift_source.push_str(&widget_bundle);

    let mut swift_files = vec![(format!("{}.swift", safe_name), swift_source)];

    // Generate AppIntent configuration if config params exist
    if !widget.config_params.is_empty() {
        let intent_source = emit::emit_app_intent_config(widget, &safe_name);
        let mut intent_file = String::new();
        intent_file.push_str("// Auto-generated by Perry compiler — do not edit\n");
        intent_file.push_str("import AppIntents\n\n");
        intent_file.push_str(&intent_source);
        swift_files.push((format!("{}Intent.swift", safe_name), intent_file));
    }

    // Generate native bridge glue if provider function exists
    if widget.provider_func_name.is_some() || widget.app_group.is_some() {
        let glue_source = emit::emit_glue(widget, &safe_name);
        swift_files.push((format!("{}Glue.swift", safe_name), glue_source));
    }

    let info_plist = generate_info_plist(&bundle_id, &widget.display_name);

    Ok(WidgetBundle {
        swift_files,
        info_plist,
        bundle_id,
    })
}

/// Generate Info.plist for the widget extension
fn generate_info_plist(bundle_id: &str, display_name: &str) -> String {
    format!(
        r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleDisplayName</key>
    <string>{display_name}</string>
    <key>CFBundleExecutable</key>
    <string>$(EXECUTABLE_NAME)</string>
    <key>CFBundleIdentifier</key>
    <string>{bundle_id}</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$(PRODUCT_NAME)</string>
    <key>CFBundlePackageType</key>
    <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>NSExtension</key>
    <dict>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.widgetkit-extension</string>
    </dict>
</dict>
</plist>"#,
        display_name = display_name,
        bundle_id = bundle_id,
    )
}

/// Convert widget kind (e.g., "com.example.MyWidget") to a safe Swift identifier
fn sanitize_kind(kind: &str) -> String {
    // Use the last component as the name
    let last = kind.rsplit('.').next().unwrap_or(kind);
    let mut result = String::with_capacity(last.len());
    for c in last.chars() {
        if c.is_alphanumeric() || c == '_' {
            result.push(c);
        }
    }
    if result.is_empty() {
        "PerryWidget".to_string()
    } else {
        result
    }
}
