#![deny(missing_docs)]
//! Procedural macros for the textual-rs TUI framework.

mod derive_widget;
mod widget_impl;

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

/// Derive macro that generates inherent `__` helper methods on the struct.
///
/// Generates:
/// - `fn __widget_type_name() -> &'static str`
/// - `fn __can_focus() -> bool`
/// - `fn __on_mount(&self, id: WidgetId)`
/// - `fn __on_unmount(&self, _id: WidgetId)`
///
/// Does NOT generate `impl Widget for T` — use `#[widget_impl]` on your impl block instead.
///
/// The struct MUST declare `own_id: std::cell::Cell<Option<WidgetId>>` itself.
///
/// Optional attributes:
/// - `#[focusable]` — makes `__can_focus()` return `true`
///
/// # Example
/// ```ignore
/// #[derive(Widget)]
/// #[focusable]
/// struct MyWidget {
///     own_id: Cell<Option<WidgetId>>,
///     label: String,
/// }
///
/// #[widget_impl]
/// impl Widget for MyWidget {
///     fn render(&self, ctx: &AppContext, area: Rect, buf: &mut Buffer) {
///         // ...
///     }
/// }
/// ```
#[proc_macro_derive(Widget, attributes(focusable))]
pub fn derive_widget(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    derive_widget::derive_widget_impl(input).into()
}

/// Attribute macro for `impl Widget for MyStruct` blocks.
///
/// Injects delegation methods that call the `__` helper methods generated by `#[derive(Widget)]`:
/// - `fn widget_type_name(&self) -> &'static str { Self::__widget_type_name() }`
/// - `fn can_focus(&self) -> bool { Self::__can_focus() }`
/// - `fn on_mount(&self, id: WidgetId) { self.__on_mount(id); }`
/// - `fn on_unmount(&self, id: WidgetId) { self.__on_unmount(id); }`
///
/// Also collects method annotations:
/// - `#[on(MsgType)]` — dispatches that message type in `on_event()`
/// - `#[keybinding("key_combo", "action_name")]` — adds to `key_bindings()` and `on_action()`
///
/// Methods you already define in the impl block will NOT be duplicated.
#[proc_macro_attribute]
pub fn widget_impl(_args: TokenStream, input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as syn::ItemImpl);
    widget_impl::widget_impl_transform(input).into()
}
