//! Tests for Svelte code extraction.

use super::common::*;
use crate::embed::build_embedding_text;
use crate::parser::Language;

#[test]
fn test_basic_component() {
    let source = r#"<script>
    let count = 0;

    function increment() {
        count += 1;
    }
</script>

<button on:click={increment}>
    Clicked {count} times
</button>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");
    assert_eq!(units.len(), 3);

    let text = build_embedding_text(&units[0]);
    assert_eq!(text, "    let count = 0;");

    let text = build_embedding_text(&units[1]);
    assert_eq!(
        text,
        "Function: increment
Signature: function increment() {
File: test test.svelte
Code:
    function increment() {
        count += 1;
    }"
    );

    let text = build_embedding_text(&units[2]);
    assert_eq!(
        text,
        "<button on:click={increment}>
    Clicked {count} times
</button>"
    );
}

#[test]
fn test_reactive_declarations() {
    let source = r#"<script>
    let count = 0;
    $: doubled = count * 2;
    $: quadrupled = doubled * 2;

    function increment() {
        count += 1;
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");
    assert_eq!(units.len(), 2);

    let text = build_embedding_text(&units[0]);
    assert_eq!(text, "    let count = 0;");

    let text = build_embedding_text(&units[1]);
    assert_eq!(
        text,
        "Function: increment
Signature: function increment() {
File: test test.svelte
Code:
    function increment() {
        count += 1;
    }"
    );
}

#[test]
fn test_props() {
    let source = r#"<script>
    export let name = 'World';
    export let greeting = 'Hello';

    function greet() {
        return `${greeting}, ${name}!`;
    }
</script>"#;
    let units = parse(source, Language::Svelte, "test.svelte");
    assert_eq!(units.len(), 3);

    let name_unit = get_unit_by_name(&units, "name").unwrap();
    let name_text = build_embedding_text(name_unit);
    assert_eq!(name_text, "    export let name = 'World';");

    let greet_unit = get_unit_by_name(&units, "greet").unwrap();
    let greet_text = build_embedding_text(greet_unit);
    let expected_greet = r#"Function: greet
Signature: function greet() {
File: test test.svelte
Code:
    function greet() {
        return `${greeting}, ${name}!`;
    }"#;
    assert_eq!(greet_text, expected_greet);
}

#[test]
fn test_typescript_support() {
    let source = r#"
<script lang="ts">
    interface User {
        name: string;
        age: number;
    }

    export let user: User;

    function getDisplayName(user: User): string {
        return `${user.name} (${user.age})`;
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract TypeScript component");
}

#[test]
fn test_stores() {
    let source = r#"
<script>
    import { writable } from 'svelte/store';

    const count = writable(0);

    function increment() {
        count.update(n => n + 1);
    }

    function reset() {
        count.set(0);
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract stores");
}

#[test]
fn test_lifecycle_functions() {
    let source = r#"
<script>
    import { onMount, onDestroy } from 'svelte';

    let data = null;

    onMount(async () => {
        const response = await fetch('/api/data');
        data = await response.json();
    });

    onDestroy(() => {
        console.log('Component destroyed');
    });
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract lifecycle functions");
}

#[test]
fn test_event_handlers() {
    let source = r#"
<script>
    function handleClick(event) {
        console.log('Clicked!', event);
    }

    function handleInput(event) {
        console.log('Input:', event.target.value);
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract event handlers");
}

#[test]
fn test_context_api() {
    let source = r#"
<script>
    import { setContext, getContext } from 'svelte';

    const key = Symbol();

    function setTheme(theme) {
        setContext(key, theme);
    }

    function getTheme() {
        return getContext(key);
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract context API");
}

#[test]
fn test_slots_and_props() {
    let source = r#"
<script>
    export let title = 'Default Title';
    export let subtitle = '';

    function formatTitle(title) {
        return title.toUpperCase();
    }
</script>

<div>
    <h1>{formatTitle(title)}</h1>
    {#if subtitle}
        <h2>{subtitle}</h2>
    {/if}
    <slot />
</div>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract slots and props");
}

#[test]
fn test_async_await() {
    let source = r#"
<script>
    let promise = null;

    async function fetchData(url) {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error('Network error');
        }
        return response.json();
    }

    function load() {
        promise = fetchData('/api/data');
    }
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");

    assert!(!units.is_empty(), "Should extract async functions");
}

#[test]
fn test_function_with_imports() {
    let source = r#"<script>
import axios from 'axios';

async function fetchUsers() {
    const response = await axios.get('/api/users');
    return response.data;
}
</script>
"#;
    let units = parse(source, Language::Svelte, "test.svelte");
    let func = get_unit_by_name(&units, "fetchUsers").unwrap();
    let text = build_embedding_text(func);

    let expected = r#"Function: fetchUsers
Signature: async function fetchUsers() {
Calls: get
Variables: const, response
Uses: axios
File: test test.svelte
Code:
async function fetchUsers() {
    const response = await axios.get('/api/users');
    return response.data;
}"#;
    assert_eq!(text, expected);
}
