//! # sylpheed-viewer
//!
//! Bevy-based asset viewer for Project Sylpheed: Arc of Deception.
//!
//! This crate serves as both:
//! - A **native binary** (via `main.rs`) — full desktop viewer
//! - A **WASM library** (this file) — browser viewer at `index.html`
//!
//! ## Architecture
//! - `sylpheed_formats` handles all binary parsing — no Bevy dependency
//! - This crate is the thin Bevy integration layer on top
//! - `asset_loader` bridges the two: wraps parsers as `AssetLoader` impls
//!
//! ## WASM notes
//! On the web, local file access is unavailable. Assets must be
//! pre-extracted and served over HTTP. XISO reading is native-only.

use bevy::prelude::*;
use bevy_egui::EguiPlugin;

pub mod asset_loader;
pub mod camera;
pub mod iso_loader;
pub mod ui;

// ── Application state ────────────────────────────────────────────────────────

/// Global viewer state, shared across all UI and rendering systems.
#[derive(Resource)]
pub struct ViewerState {
    /// Whether the plain-text viewer wraps long lines.
    pub text_wrap: bool,
}

impl Default for ViewerState {
    fn default() -> Self {
        Self { text_wrap: true }
    }
}

// ── App builder ──────────────────────────────────────────────────────────────

/// Build and run the viewer application.
///
/// Called from `main.rs` on native and from `wasm_bindgen` init on the web.
pub fn run() {
    let mut app = App::new();

    app.add_plugins(
        DefaultPlugins.set(WindowPlugin {
            primary_window: Some(Window {
                title: "Project Sylpheed: Arc of Deception — Asset Viewer".into(),
                resolution: (1280.0, 720.0).into(),
                ..default()
            }),
            ..default()
        }),
    );

    app.add_plugins(EguiPlugin);
    app.add_plugins(asset_loader::SylpheedAssetPlugin);
    app.add_plugins(iso_loader::IsoLoaderPlugin);
    app.add_plugins(camera::OrbitCameraPlugin);
    app.add_plugins(ui::ViewerUiPlugin);

    app.init_resource::<ViewerState>();

    // Minimal 3D scene: a directional light so meshes are visible
    app.add_systems(Startup, setup_scene);

    app.run();
}

fn setup_scene(mut commands: Commands) {
    // Bright ambient so surfaces facing away from every light aren't pure black.
    commands.insert_resource(AmbientLight {
        color: Color::srgb(0.9, 0.93, 1.0),
        brightness: 900.0,
    });
    // A multi-directional rig (key + fills + rim + underside) so an orbiting
    // camera always has some light on the visible side — the single front light
    // left the backside unreadable.
    let lights = [
        (Vec3::new(1.0, 2.0, 1.5), 10_000.0, true),  // key: front-top-right
        (Vec3::new(-2.0, 1.0, 0.5), 4_500.0, false), // fill: left
        (Vec3::new(0.5, 0.8, -2.0), 6_000.0, false), // rim: behind
        (Vec3::new(0.0, -1.5, 0.5), 2_500.0, false), // underside fill
    ];
    for (from, lux, shadows) in lights {
        commands.spawn((
            DirectionalLight {
                illuminance: lux,
                shadows_enabled: shadows,
                ..default()
            },
            Transform::from_translation(from).looking_at(Vec3::ZERO, Vec3::Y),
        ));
    }
}
