//! Smoke test for the channels target against a synthetic fixture.
//! The JS channels.mjs runs types through `openapi-typescript` which the
//! Rust codegen replaces with direct interface emission; byte-equivalence
//! against the JS baseline is intentionally not the gate. Instead this
//! test checks structural properties of the emitted output.

use std::collections::BTreeMap;
use std::path::PathBuf;

use mizan_codegen::config::{Config, SourceConfig};
use mizan_codegen::emit::CodegenTarget;
use mizan_codegen::emit::channels::ChannelsTarget;
use mizan_codegen::fetch::parse_ir_from_str;


fn fixture_config() -> Config {
    Config {
        project_id: None,
        output: PathBuf::from("/tmp"),
        targets: vec!["channels".to_string()],
        source: SourceConfig { fastapi: None, django: None, rust: None, script: None },
        rust_kernel: None,
        rust_crate_name: None,
    }
}


#[test]
fn channels_target_emits_expected_files() {
    let raw = std::fs::read_to_string(
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/channels_ir.kdl"),
    ).unwrap();
    let ir = parse_ir_from_str(&raw).unwrap();

    let files = ChannelsTarget.emit(&ir, &fixture_config());
    assert_eq!(files.len(), 2, "channels target emits 2 files when channels present");

    let by_path: BTreeMap<PathBuf, &str> =
        files.iter().map(|f| (f.rel_path.clone(), f.content.as_str())).collect();

    let ts = by_path.get(&PathBuf::from("channels.ts"))
        .expect("channels.ts emitted");
    for expected in [
        "export interface ChatChannelParams",
        "export interface ChatReactMessage",
        "export interface ChatDjangoMessage",
        "export interface NotificationsDjangoMessage",
        "export const CHANNELS = {",
        "chat: {",
        "notifications: {",
        "hasParams: true",
        "hasParams: false",
    ] {
        assert!(ts.contains(expected), "channels.ts must contain {expected:?}");
    }

    let hooks = by_path.get(&PathBuf::from("channels.hooks.tsx"))
        .expect("channels.hooks.tsx emitted");
    for expected in [
        "import { useChannel, type ChannelSubscription } from 'mizan/channels'",
        "export function useChatChannel(params: ChatChannelParams)",
        "export function useNotificationsChannel()",
        "ChannelSubscription<ChatChannelParams, ChatDjangoMessage, ChatReactMessage>",
        "ChannelSubscription<Record<string, never>, NotificationsDjangoMessage, never>",
    ] {
        assert!(hooks.contains(expected), "channels.hooks.tsx must contain {expected:?}");
    }
}


#[test]
fn channels_target_emits_nothing_when_empty() {
    // AFI fixture has no channels — target should produce zero files.
    let raw = std::fs::read_to_string(
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/afi_ir.kdl"),
    ).unwrap();
    let ir = parse_ir_from_str(&raw).unwrap();
    let files = ChannelsTarget.emit(&ir, &fixture_config());
    assert!(files.is_empty(), "no channels → no files");
}
