//! Catalog delegations that let `iced_ui::Theme` style the iced
//! built-in widgets.
//!
//! Most impls are auto-generated by `build.rs`, which scans the
//! `iced_widget` source for `pub trait Catalog` definitions and emits
//! macro invocations that expand into forwarding implementations.
//!
//! A handful of traits require hand-written impls because they don't
//! fit the standard macro pattern (e.g. `theme::Base`, `text`,
//! `markdown`).
//!
//! If a new iced widget appears and is not yet covered, consumers can
//! use [`native()`](crate::native) as an escape hatch while waiting
//! for the next `iced_ui` release.

use iced::theme as iced_theme;
use iced::widget::text;
#[cfg(feature = "markdown")]
use iced::widget::{container, markdown};

use crate::Theme;

// ─── Forwarding macro ────────────────────────────────────────────────
//
// Generates an `impl $widget::Catalog for Theme` that delegates styling
// to the inner `iced::Theme` stored in `Theme::colors`.
//
// Four arms cover the full matrix of:
//   • with / without a `Status` parameter in `style()`
//   • delegates to a named style fn / returns `Style::default()`

/// Delegates an iced widget `Catalog` trait to the inner `iced::Theme`.
macro_rules! impl_iced_catalog {
    // ── With Status, delegates to a named function ──
    ($($path:ident)::+, $default_fn:ident) => {
        impl iced::widget::$($path)::+::Catalog for Theme {
            type Class<'a> = iced::widget::$($path)::+::StyleFn<'a, Theme>;

            fn default<'a>() -> <Self as iced::widget::$($path)::+::Catalog>::Class<'a> {
                Box::new(|theme: &Theme, status| {
                    iced::widget::$($path)::+::$default_fn(&theme.colors, status)
                })
            }

            fn style(
                &self,
                class: &<Self as iced::widget::$($path)::+::Catalog>::Class<'_>,
                status: iced::widget::$($path)::+::Status,
            ) -> iced::widget::$($path)::+::Style {
                class(self, status)
            }
        }
    };

    // ── Without Status, delegates to a named function ──
    (no_status $($path:ident)::+, $default_fn:ident) => {
        impl iced::widget::$($path)::+::Catalog for Theme {
            type Class<'a> = iced::widget::$($path)::+::StyleFn<'a, Theme>;

            fn default<'a>() -> <Self as iced::widget::$($path)::+::Catalog>::Class<'a> {
                Box::new(|theme: &Theme| {
                    iced::widget::$($path)::+::$default_fn(&theme.colors)
                })
            }

            fn style(
                &self,
                class: &<Self as iced::widget::$($path)::+::Catalog>::Class<'_>,
            ) -> iced::widget::$($path)::+::Style {
                class(self)
            }
        }
    };

    // ── With Status, returns Style::default() ──
    (style_default $($path:ident)::+) => {
        impl iced::widget::$($path)::+::Catalog for Theme {
            type Class<'a> = iced::widget::$($path)::+::StyleFn<'a, Theme>;

            fn default<'a>() -> <Self as iced::widget::$($path)::+::Catalog>::Class<'a> {
                Box::new(|_theme: &Theme, _status| iced::widget::$($path)::+::Style::default())
            }

            fn style(
                &self,
                class: &<Self as iced::widget::$($path)::+::Catalog>::Class<'_>,
                status: iced::widget::$($path)::+::Status,
            ) -> iced::widget::$($path)::+::Style {
                class(self, status)
            }
        }
    };

    // ── Without Status, returns Style::default() ──
    (no_status style_default $($path:ident)::+) => {
        impl iced::widget::$($path)::+::Catalog for Theme {
            type Class<'a> = iced::widget::$($path)::+::StyleFn<'a, Theme>;

            fn default<'a>() -> <Self as iced::widget::$($path)::+::Catalog>::Class<'a> {
                Box::new(|_theme: &Theme| iced::widget::$($path)::+::Style::default())
            }

            fn style(
                &self,
                class: &<Self as iced::widget::$($path)::+::Catalog>::Class<'_>,
            ) -> iced::widget::$($path)::+::Style {
                class(self)
            }
        }
    };
}

// ─── Auto-generated invocations ──────────────────────────────────────
// build.rs scans iced_widget source and emits one macro call per
// discovered Catalog trait (plus marker impls and comments for specials).
include!(concat!(env!("OUT_DIR"), "/iced_catalog_impls.rs"));

// ─── Hand-written: text::Catalog ─────────────────────────────────────
// Defined in iced_core (not iced_widget), so the build script doesn't
// discover it.
impl text::Catalog for Theme {
    type Class<'a> = text::StyleFn<'a, Theme>;

    fn default<'a>() -> Self::Class<'a> {
        Box::new(|_theme| text::Style::default())
    }

    fn style(&self, class: &Self::Class<'_>) -> text::Style {
        class(self)
    }
}

// ─── Hand-written: theme::Base ───────────────────────────────────────

impl iced_theme::Base for Theme {
    fn default(preference: iced_theme::Mode) -> Self {
        Self::from(<iced::Theme as iced_theme::Base>::default(preference))
    }

    fn mode(&self) -> iced_theme::Mode {
        self.colors.mode()
    }

    fn base(&self) -> iced_theme::Style {
        self.colors.base()
    }

    fn palette(&self) -> Option<iced::theme::Palette> {
        Some(self.colors.palette())
    }

    fn name(&self) -> &str {
        self.colors.name()
    }
}

// ─── Hand-written: markdown::Catalog ─────────────────────────────────
// Has a required `code_block()` method with no default impl.
#[cfg(feature = "markdown")]
impl markdown::Catalog for Theme {
    fn code_block<'a>() -> <Self as container::Catalog>::Class<'a> {
        Box::new(|theme: &Theme| container::dark(&theme.colors))
    }
}
