use leptos::prelude::*;
use leptos::task::spawn_local;
use serde::{Deserialize, Serialize};
use web_sys::js_sys;
use wasm_bindgen::prelude::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyTemplate {
    pub id: String,
    pub name: String,
    pub description: String,
    pub category: String,
    pub content: String,
    pub variables: Vec<PolicyVariable>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyVariable {
    pub name: String,
    pub description: String,
    pub var_type: String,
    pub default_value: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyEvaluation {
    pub policy_id: String,
    pub test_cases: Vec<TestCase>,
    pub results: Vec<EvaluationResult>,
    pub impact_analysis: ImpactAnalysis,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TestCase {
    pub id: String,
    pub name: String,
    pub principal: String,
    pub action: String,
    pub resource: String,
    pub context: serde_json::Value,
    pub expected_result: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvaluationResult {
    pub test_case_id: String,
    pub decision: String,
    pub reasons: Vec<String>,
    pub passed: bool,
    pub execution_time_ms: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImpactAnalysis {
    pub affected_users: u32,
    pub affected_resources: u32,
    pub risk_level: String,
    pub recommendations: Vec<String>,
}

#[component]
pub fn PolicyEditor() -> impl IntoView {
    let (current_policy, set_current_policy) = signal(String::new());
    let (selected_template, set_selected_template) = signal(None::<PolicyTemplate>);
    let (test_results, set_test_results) = signal(None::<PolicyEvaluation>);
    let (is_testing, set_is_testing) = signal(false);
    let (show_templates, set_show_templates) = signal(false);
    let (show_diff_viewer, set_show_diff_viewer) = signal(false);
    let (policy_versions, set_policy_versions) = signal(Vec::<PolicyVersion>::new());

    let templates = signal(vec![
        PolicyTemplate {
            id: "require-mfa".to_string(),
            name: "Require Multi-Factor Authentication".to_string(),
            description: "Enforce MFA for sensitive operations".to_string(),
            category: "Security".to_string(),
            content: r#"permit (
  principal is User,
  action in [Action::"create_server", Action::"delete_server"],
  resource
) when {
  principal.mfa_enabled == true &&
  context.mfa_verified == true
};"#.to_string(),
            variables: vec![],
        },
        PolicyTemplate {
            id: "production-approval".to_string(),
            name: "Production Environment Approval".to_string(),
            description: "Require approval for production changes".to_string(),
            category: "Governance".to_string(),
            content: r#"permit (
  principal is User,
  action,
  resource is Infrastructure
) when {
  resource.environment != "production" ||
  (resource.environment == "production" &&
   context.approval_count >= {{min_approvals}})
};"#.to_string(),
            variables: vec![
                PolicyVariable {
                    name: "min_approvals".to_string(),
                    description: "Minimum number of approvals required".to_string(),
                    var_type: "number".to_string(),
                    default_value: Some("2".to_string()),
                },
            ],
        },
        PolicyTemplate {
            id: "time-based-access".to_string(),
            name: "Time-Based Access Control".to_string(),
            description: "Restrict access to business hours".to_string(),
            category: "Access Control".to_string(),
            content: r#"permit (
  principal is User,
  action,
  resource
) when {
  context.current_time >= time("{{start_time}}") &&
  context.current_time <= time("{{end_time}}") &&
  context.day_of_week in {{allowed_days}}
};"#.to_string(),
            variables: vec![
                PolicyVariable {
                    name: "start_time".to_string(),
                    description: "Start time (HH:MM format)".to_string(),
                    var_type: "time".to_string(),
                    default_value: Some("09:00".to_string()),
                },
                PolicyVariable {
                    name: "end_time".to_string(),
                    description: "End time (HH:MM format)".to_string(),
                    var_type: "time".to_string(),
                    default_value: Some("17:00".to_string()),
                },
                PolicyVariable {
                    name: "allowed_days".to_string(),
                    description: "Allowed days of week".to_string(),
                    var_type: "array".to_string(),
                    default_value: Some(r#"["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]"#.to_string()),
                },
            ],
        },
    ]).0;

    // Initialize Monaco Editor
    Effect::new(move |_| {
        let editor_element = web_sys::window()
            .unwrap()
            .document()
            .unwrap()
            .get_element_by_id("monaco-editor");

        if let Some(element) = editor_element {
            // Initialize Monaco with Cedar syntax highlighting
            init_monaco_editor(&element, current_policy.get());
        }
    });

    let run_policy_test = move || {
        set_is_testing.set(true);

        // Simulate policy evaluation
        spawn_local(async move {
            // In a real implementation, this would call the Cedar engine
            let mock_results = PolicyEvaluation {
                policy_id: "test-policy".to_string(),
                test_cases: vec![
                    TestCase {
                        id: "test-1".to_string(),
                        name: "Admin with MFA".to_string(),
                        principal: "User::\"admin\"".to_string(),
                        action: "Action::\"create_server\"".to_string(),
                        resource: "Resource::\"production\"".to_string(),
                        context: serde_json::json!({
                            "mfa_enabled": true,
                            "mfa_verified": true
                        }),
                        expected_result: "Allow".to_string(),
                    },
                ],
                results: vec![
                    EvaluationResult {
                        test_case_id: "test-1".to_string(),
                        decision: "Allow".to_string(),
                        reasons: vec!["MFA requirements satisfied".to_string()],
                        passed: true,
                        execution_time_ms: 15,
                    },
                ],
                impact_analysis: ImpactAnalysis {
                    affected_users: 25,
                    affected_resources: 100,
                    risk_level: "Medium".to_string(),
                    recommendations: vec![
                        "Consider adding time-based restrictions".to_string(),
                        "Monitor for policy violations".to_string(),
                    ],
                },
            };

            set_test_results.set(Some(mock_results));
            set_is_testing.set(false);
        });
    };

    view! {
        <div class="policy-editor h-full flex flex-col">
            <div class="flex-none border-b border-base-300 p-4">
                <div class="flex items-center justify-between">
                    <h2 class="text-2xl font-bold">"Cedar Policy Editor"</h2>
                    <div class="flex gap-2">
                        <button
                            class="btn btn-outline btn-sm"
                            on:click=move |_| set_show_templates.set(!show_templates.get())
                        >
                            "Templates"
                        </button>
                        <button
                            class="btn btn-outline btn-sm"
                            on:click=move |_| set_show_diff_viewer.set(!show_diff_viewer.get())
                        >
                            "Version History"
                        </button>
                        <button
                            class="btn btn-primary btn-sm"
                            on:click=move |_| run_policy_test()
                            disabled=move || is_testing.get()
                        >
                            {move || if is_testing.get() { "Testing..." } else { "Test Policy" }}
                        </button>
                    </div>
                </div>
            </div>

            <div class="flex-1 flex">
                // Left Panel - Editor and Templates
                <div class="flex-1 flex flex-col">
                    // Template Library
                    {move || if show_templates.get() {
                        view! {
                            <div class="h-48 border-b border-base-300 p-4">
                                <h3 class="font-semibold mb-3">"Policy Templates"</h3>
                                <div class="grid grid-cols-1 md:grid-cols-3 gap-2">
                                    {templates.get().into_iter().map(|template| {
                                        let template_clone = template.clone();
                                        view! {
                                            <div class="card bg-base-200 p-3 cursor-pointer hover:bg-base-300"
                                                on:click=move |_| {
                                                    set_current_policy.set(template_clone.content.clone());
                                                    set_selected_template.set(Some(template_clone.clone()));
                                                    set_show_templates.set(false);
                                                }
                                            >
                                                <h4 class="font-medium text-sm">{&template.name}</h4>
                                                <p class="text-xs text-base-content/70 mt-1">{&template.description}</p>
                                                <div class="badge badge-outline badge-xs mt-2">{&template.category}</div>
                                            </div>
                                        }
                                    }).collect::<Vec<_>>()}
                                </div>
                            </div>
                        }.into()
                    } else {
                        view! { <div></div> }.into()
                    }}

                    // Monaco Editor
                    <div class="flex-1 relative">
                        <div id="monaco-editor" class="w-full h-full"></div>
                    </div>

                    // Syntax and Validation Errors
                    <div class="flex-none h-32 border-t border-base-300 bg-base-100 p-4">
                        <h3 class="font-semibold mb-2">"Syntax Check"</h3>
                        <div class="text-sm text-success">
                            "✓ Policy syntax is valid"
                        </div>
                    </div>
                </div>

                // Right Panel - Testing and Results
                <div class="w-1/3 border-l border-base-300 flex flex-col">
                    // Test Cases
                    <div class="flex-none p-4 border-b border-base-300">
                        <h3 class="font-semibold mb-3">"Test Scenarios"</h3>
                        <TestCaseBuilder />
                    </div>

                    // Results
                    <div class="flex-1 p-4">
                        {move || {
                            if let Some(results) = test_results.get() {
                                view! {
                                    <div>
                                        <h3 class="font-semibold mb-3">"Test Results"</h3>
                                        {results.results.into_iter().map(|result| {
                                            view! {
                                                <div class="mb-3 p-3 rounded border border-base-300">
                                                    <div class="flex items-center justify-between mb-2">
                                                        <span class="font-medium">{result.test_case_id}</span>
                                                        <div class={format!("badge {}",
                                                            if result.passed { "badge-success" } else { "badge-error" }
                                                        )}>
                                                            {result.decision}
                                                        </div>
                                                    </div>
                                                    <div class="text-sm text-base-content/70">
                                                        {result.reasons.join(", ")}
                                                    </div>
                                                    <div class="text-xs text-base-content/50 mt-1">
                                                        {format!("{}ms", result.execution_time_ms)}
                                                    </div>
                                                </div>
                                            }
                                        }).collect::<Vec<_>>()}

                                        // Impact Analysis
                                        <div class="mt-4 p-3 bg-base-200 rounded">
                                            <h4 class="font-medium mb-2">"Impact Analysis"</h4>
                                            <div class="text-sm space-y-1">
                                                <div>"Affected Users: " {results.impact_analysis.affected_users}</div>
                                                <div>"Affected Resources: " {results.impact_analysis.affected_resources}</div>
                                                <div>"Risk Level: "
                                                    <span class={format!("badge badge-{}",
                                                        match results.impact_analysis.risk_level.as_str() {
                                                            "Low" => "success",
                                                            "Medium" => "warning",
                                                            "High" => "error",
                                                            _ => "neutral"
                                                        }
                                                    )}>
                                                        {&results.impact_analysis.risk_level}
                                                    </span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                }.into()
                            } else {
                                view! {
                                    <div class="text-center text-base-content/50 mt-8">
                                        "Run tests to see results"
                                    </div>
                                }.into()
                            }
                        }}
                    </div>
                </div>
            </div>

            // Version Diff Viewer Modal
            {move || if show_diff_viewer.get() {
                view! {
                    <div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
                        <div class="bg-base-100 rounded-lg w-4/5 h-4/5 flex flex-col">
                            <div class="flex-none p-4 border-b border-base-300 flex justify-between items-center">
                                <h3 class="text-lg font-semibold">"Policy Version History"</h3>
                                <button
                                    class="btn btn-ghost btn-sm"
                                    on:click=move |_| set_show_diff_viewer.set(false)
                                >
                                    "✕"
                                </button>
                            </div>
                            <div class="flex-1 p-4">
                                <PolicyDiffViewer />
                            </div>
                        </div>
                    </div>
                }.into()
            } else {
                view! { <div></div> }.into()
            }}
        </div>
    }
}

#[component]
fn TestCaseBuilder() -> impl IntoView {
    let (principal, set_principal) = signal("User::\"alice\"".to_string());
    let (action, set_action) = signal("Action::\"read\"".to_string());
    let (resource, set_resource) = signal("Resource::\"document\"".to_string());

    view! {
        <div class="space-y-3">
            <div>
                <label class="label label-text text-xs">"Principal"</label>
                <input
                    type="text"
                    class="input input-bordered input-sm w-full"
                    prop:value=move || principal.get()
                    on:input=move |ev| set_principal.set(event_target_value(&ev))
                />
            </div>
            <div>
                <label class="label label-text text-xs">"Action"</label>
                <input
                    type="text"
                    class="input input-bordered input-sm w-full"
                    prop:value=move || action.get()
                    on:input=move |ev| set_action.set(event_target_value(&ev))
                />
            </div>
            <div>
                <label class="label label-text text-xs">"Resource"</label>
                <input
                    type="text"
                    class="input input-bordered input-sm w-full"
                    prop:value=move || resource.get()
                    on:input=move |ev| set_resource.set(event_target_value(&ev))
                />
            </div>
            <button class="btn btn-outline btn-sm w-full">"Add Test Case"</button>
        </div>
    }
}

#[component]
fn PolicyDiffViewer() -> impl IntoView {
    view! {
        <div class="h-full flex">
            <div class="w-1/4 border-r border-base-300 pr-4">
                <h4 class="font-medium mb-3">"Versions"</h4>
                <div class="space-y-2">
                    <div class="p-2 bg-primary text-primary-content rounded text-sm">
                        "v1.2.0 (current)"
                        <div class="text-xs opacity-70">"2024-01-15"</div>
                    </div>
                    <div class="p-2 bg-base-200 rounded text-sm cursor-pointer hover:bg-base-300">
                        "v1.1.0"
                        <div class="text-xs opacity-70">"2024-01-10"</div>
                    </div>
                    <div class="p-2 bg-base-200 rounded text-sm cursor-pointer hover:bg-base-300">
                        "v1.0.0"
                        <div class="text-xs opacity-70">"2024-01-01"</div>
                    </div>
                </div>
            </div>
            <div class="flex-1 pl-4">
                <h4 class="font-medium mb-3">"Changes in v1.2.0"</h4>
                <div class="font-mono text-sm bg-base-200 p-4 rounded">
                    <div class="text-success">"+ Added MFA requirement for sensitive actions"</div>
                    <div class="text-error">"- Removed time-based restrictions"</div>
                    <div class="text-info">"~ Modified approval threshold from 1 to 2"</div>
                </div>
            </div>
        </div>
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyVersion {
    pub id: String,
    pub version: String,
    pub created_at: String,
    pub author: String,
    pub changes: String,
}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = ["window", "monaco", "editor"])]
    fn create(element: &web_sys::Element, options: &js_sys::Object) -> js_sys::Object;
}

fn init_monaco_editor(element: &web_sys::Element, initial_value: String) {
    let options = js_sys::Object::new();
    js_sys::Reflect::set(&options, &"value".into(), &initial_value.into()).unwrap();
    js_sys::Reflect::set(&options, &"language".into(), &"cedar".into()).unwrap();
    js_sys::Reflect::set(&options, &"theme".into(), &"vs-dark".into()).unwrap();

    create(element, &options);
}
