/// Frosted toolbar (title + orbs, backdrop blur). **Placement is up to the parent**
/// — [KasyAppBar] does not force one layout.
///
/// **1 — Underlap (content behind the frost)**
/// Use [KasyOverlayScaffold] or a [Stack]: scroll view fills the screen; first sliver
/// uses [kasyAppBarBodyTopOverlap]; bar in a [Positioned] at `top: 0`. Best for
/// home, long lists, previews.
///
/// **2 — No underlap (bar sits above content)**
/// `[Column]` → `[KasyAppBar]` → `[Expanded]` → your scroll/list, with
/// [KasySpacing.belowChromeContentGap] above the scroll child. Nothing scrolls under
/// the bar (e.g. catalog with an inset list).
///
/// **3 — Bar scrolls away with content**
/// Put [KasyAppBar] *inside* the same scroll view (e.g. first `SliverToBoxAdapter`
/// or top of a [ListView]). Bar and body move together.
///
/// **Styles:** [KasyAppBarStyle.subpage] (back + theme), [KasyAppBarStyle.rootTab],
/// [KasyAppBarStyle.subpageSimple] (back only), [KasyAppBarStyle.subpageActions]
/// (custom [trailing]).
///
/// Barrel: [components.dart].

library;

import 'dart:ui' show ImageFilter;

import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show SystemUiOverlayStyle;
import 'package:kasy_kit/core/theme/theme.dart';

/// Inner toolbar band height (orbit hit targets, title baseline).
const double kasyAppBarToolbarRowHeight = 44;
const double kasyAppBarTitleFontScale = 0.92;

/// Tight vertical padding inside the frost, above/below [kasyAppBarToolbarRowHeight].
const double kasyAppBarChromePaddingTop = KasySpacing.xs;
const double kasyAppBarChromePaddingBottom = KasySpacing.sm;

/// How [KasyAppBar] interacts with vertically scrolling siblings.
///
/// - [overlay]: put the bar in a [Stack] on top of the scrolling body and pad
///   the body's top with [kasyAppBarBodyTopOverlap].
/// - [intrinsicScroll]: bar is above an [Expanded] list / scroll (e.g.
///   [Column])—no blur underlap below the frost.
enum KasyAppBarScrollTreatment { overlay, intrinsicScroll }

/// Vertical inset for scroll/viewport when using [KasyAppBarScrollTreatment.overlay].
double kasyAppBarBodyTopOverlap(BuildContext context) {
  return MediaQuery.paddingOf(context).top +
      kasyAppBarChromePaddingTop +
      kasyAppBarToolbarRowHeight +
      kasyAppBarChromePaddingBottom;
}

/// Overlap spacer + padded sliver group for overlay chrome.
///
/// Use inside a [CustomScrollView] under a pinned [KasyAppBar] in a [Stack], or use
/// [KasyOverlayScaffold] which applies this for you.
List<Widget> kasyOverlayPaddedSlivers(
  BuildContext context, {
  required List<Widget> slivers,
  EdgeInsetsGeometry? contentPadding,
}) {
  final EdgeInsetsGeometry pad =
      contentPadding ??
      EdgeInsets.fromLTRB(
        KasySpacing.pageHorizontalGutter,
        KasySpacing.belowChromeContentGap,
        KasySpacing.pageHorizontalGutter,
        MediaQuery.paddingOf(context).bottom + KasySpacing.pageVerticalGutter,
      );
  return <Widget>[
    SliverToBoxAdapter(
      child: SizedBox(height: kasyAppBarBodyTopOverlap(context)),
    ),
    SliverPadding(
      padding: pad,
      sliver: SliverMainAxisGroup(slivers: slivers),
    ),
  ];
}

/// Orbs vs canvas: slightly lifted in dark so they read off [KasyColors.background];
/// soft chip in light, close to frost.
Color kasyChromeOrbFillColor(BuildContext context) {
  final KasyColors colors = context.colors;
  if (Theme.of(context).brightness == Brightness.dark) {
    return Color.lerp(colors.background, colors.surface, 0.32)!;
  }
  return Color.lerp(colors.surface, colors.background, 0.05)!;
}

/// Same frosted/backdrop tint and blur as [KasyAppBar] for custom pinned chrome
/// when a full bar is not used.
class KasyFrostedChromeBackground extends StatelessWidget {
  final Widget child;

  /// Backdrop blur strength; higher = more frosted (content still visible through tint).
  final double blurSigma;

  /// Insets content below the notch but keeps tint/blur covering the status-bar
  /// strip so scroll never shows cards behind clock/battery icons.
  final bool padForStatusBar;

  const KasyFrostedChromeBackground({
    super.key,
    required this.child,
    this.blurSigma = 14,
    this.padForStatusBar = true,
  });

  /// Translucent tint so blurred content shows through; tuned per brightness.
  Color _tint(BuildContext context) {
    final bool dark = Theme.of(context).brightness == Brightness.dark;
    if (dark) {
      return const Color(0xFF161618).withValues(alpha: 0.88);
    }
    // White (surface) instead of background grey so the bar lifts off the canvas.
    return const Color(0xFFFFFFFF).withValues(alpha: 0.82);
  }

  @override
  Widget build(BuildContext context) {
    final Widget content = padForStatusBar
        ? Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              SizedBox(height: MediaQuery.paddingOf(context).top),
              child,
            ],
          )
        : child;

    final Color tint = _tint(context);
    final bool dark = Theme.of(context).brightness == Brightness.dark;
    final BoxShadow baseShadow = KasyShadows.component(context);
    // Stronger shadow multiplier in light mode so the white bar reads off the grey canvas.
    final double shadowAlphaFactor = dark ? 0.4 : 0.58;
    final List<BoxShadow> chromeShadow = <BoxShadow>[
      baseShadow.copyWith(
        color: baseShadow.color.withValues(alpha: baseShadow.color.a * shadowAlphaFactor),
        blurRadius: baseShadow.blurRadius + 0.15,
        spreadRadius: baseShadow.spreadRadius - 0.1,
        offset: Offset(baseShadow.offset.dx, baseShadow.offset.dy + 0.18),
      ),
    ];
    final SystemUiOverlayStyle overlayStyle = dark
        ? SystemUiOverlayStyle.light
        : SystemUiOverlayStyle.dark.copyWith(
            statusBarColor: Colors.transparent,
          );

    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: overlayStyle,
      child: DecoratedBox(
        decoration: BoxDecoration(boxShadow: chromeShadow),
        child: ClipRect(
          child: BackdropFilter(
            filter: ImageFilter.blur(sigmaX: blurSigma, sigmaY: blurSigma),
            child: DecoratedBox(
              decoration: BoxDecoration(color: tint),
              child: content,
            ),
          ),
        ),
      ),
    );
  }
}

/// Layout preset for [KasyAppBar] (pick one; avoids composing many public pieces).
enum KasyAppBarStyle {
  /// Back + centred title + light/dark theme toggle (dashboard sub-routes).
  subpage,

  /// Back + centred title only (balanced spacer on the right).
  subpageSimple,

  /// Back + centred title + custom [trailing] (no theme toggle).
  subpageActions,

  /// Tab root: centred title + theme orb; no back ([SizedBox] placeholder left).
  rootTab,
}

/// Implements the frosted toolbar; usage patterns described in this file header.
class KasyAppBar extends StatelessWidget {
  final String title;
  final KasyAppBarStyle style;
  final VoidCallback? onBack;

  /// Only for [KasyAppBarStyle.subpageActions]. Prefer [KasyChromeOrbIconButton]
  /// or wrap a custom 44×44 chrome control with [KasyAppBarChromeTap] for the
  /// same tap target semantics as the built-in orbs.
  final Widget? trailing;
  final bool useSafeArea;
  final double frostBlurSigma;

  /// When set, called instead of [ThemeProvider.toggle] for the theme orb
  /// ([KasyAppBarStyle.subpage], [KasyAppBarStyle.rootTab]).
  final VoidCallback? onThemeToggle;

  /// Overrides [kasyAppBarToolbarRowHeight] for contexts that need a taller bar
  /// (e.g. page-sheet modals). Defaults to [kasyAppBarToolbarRowHeight].
  final double? toolbarHeight;

  /// Extra top padding inserted inside the frosted chrome, above the toolbar
  /// row. Only useful when [useSafeArea] is false (e.g. page-sheet modals)
  /// where there is no status-bar inset to provide natural breathing room.
  final double? topInset;

  const KasyAppBar({
    super.key,
    required this.title,
    this.style = KasyAppBarStyle.subpage,
    this.onBack,
    this.trailing,
    this.useSafeArea = true,
    this.frostBlurSigma = 14,
    this.onThemeToggle,
    this.toolbarHeight,
    this.topInset,
  });

  @override
  Widget build(BuildContext context) {
    final Color orbFg = context.colors.onSurface;
    final Color orbFill = kasyChromeOrbFillColor(context);
    final VoidCallback handleBack = onBack ?? () => Navigator.maybePop(context);

    final double rowHeight = toolbarHeight ?? kasyAppBarToolbarRowHeight;
    final Widget leading = switch (style) {
      KasyAppBarStyle.rootTab => SizedBox(
        width: 44,
        height: rowHeight,
      ),
      _ => KasyChromeOrbIconButton(
        icon: KasyIcons.arrowBackIos,
        iconSize: 18,
        foregroundColor: orbFg,
        fillColor: orbFill,
        onPressed: handleBack,
        tooltip: MaterialLocalizations.of(context).backButtonTooltip,
      ),
    };

    final TextStyle? titleRef =
        context.textTheme.headlineSmall ?? context.textTheme.titleLarge;
    final TextStyle? titleStyle = titleRef?.copyWith(
      fontSize: (titleRef.fontSize ?? 24) * kasyAppBarTitleFontScale,
      fontWeight: FontWeight.w900,
      letterSpacing: -0.35,
      color: context.colors.onBackground,
    );

    final Widget bar = Padding(
      padding: const EdgeInsets.fromLTRB(
        KasySpacing.pageHorizontalGutter,
        kasyAppBarChromePaddingTop,
        KasySpacing.pageHorizontalGutter,
        kasyAppBarChromePaddingBottom,
      ),
      child: SizedBox(
        height: rowHeight,
        child: Stack(
          alignment: Alignment.center,
          children: [
            Row(
              children: [
                leading,
                const Spacer(),
                _buildTrailing(context, orbFg, orbFill),
              ],
            ),
            FittedBox(
              fit: BoxFit.scaleDown,
              child: Text(
                title,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
                style: titleStyle,
              ),
            ),
          ],
        ),
      ),
    );
    final double inset = topInset ?? 0;
    final Widget barContent = (!useSafeArea && inset > 0)
        ? Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [SizedBox(height: inset), bar],
          )
        : bar;
    return KasyFrostedChromeBackground(
      blurSigma: frostBlurSigma,
      padForStatusBar: useSafeArea,
      child: barContent,
    );
  }

  Widget _buildTrailing(BuildContext context, Color iconFg, Color orbFill) {
    final bool isDark = Theme.of(context).brightness == Brightness.dark;
    switch (style) {
      case KasyAppBarStyle.subpageActions:
        return trailing ?? const SizedBox(width: 44);
      case KasyAppBarStyle.subpageSimple:
        return const SizedBox(width: 44);
      case KasyAppBarStyle.subpage:
        return KasyChromeOrbIconButton(
          icon: isDark ? KasyIcons.lightMode : KasyIcons.darkMode,
          iconSize: 20,
          foregroundColor: iconFg,
          fillColor: orbFill,
          onPressed: () {
            final VoidCallback? custom = onThemeToggle;
            if (custom != null) {
              custom();
            } else {
              ThemeProvider.of(context).toggle();
            }
          },
          tooltip: isDark ? 'Light mode' : 'Dark mode',
        );
      case KasyAppBarStyle.rootTab:
        if (trailing != null) return trailing!;
        return KasyChromeOrbIconButton(
          icon: isDark ? KasyIcons.lightMode : KasyIcons.darkMode,
          iconSize: 20,
          foregroundColor: iconFg,
          fillColor: orbFill,
          onPressed: () {
            final VoidCallback? custom = onThemeToggle;
            if (custom != null) {
              custom();
            } else {
              ThemeProvider.of(context).toggle();
            }
          },
          tooltip: isDark ? 'Light mode' : 'Dark mode',
        );
    }
  }
}

/// Full-screen scaffold: frosted [KasyAppBar] pinned over scroll content.
class KasyOverlayScaffold extends StatelessWidget {
  final String title;
  final KasyAppBarStyle appBarStyle;
  final VoidCallback? onBack;
  final VoidCallback? onThemeToggle;
  final Widget? trailing;
  final List<Widget> slivers;
  final EdgeInsetsGeometry? contentPadding;
  final ScrollController? scrollController;
  final ScrollPhysics? physics;
  final Color? backgroundColor;
  final Future<void> Function()? onRefresh;
  final double refreshIndicatorDisplacement;

  const KasyOverlayScaffold({
    super.key,
    required this.title,
    this.appBarStyle = KasyAppBarStyle.subpage,
    this.onBack,
    this.onThemeToggle,
    this.trailing,
    required this.slivers,
    this.contentPadding,
    this.scrollController,
    this.physics,
    this.backgroundColor,
    this.onRefresh,
    this.refreshIndicatorDisplacement = 48,
  });

  @override
  Widget build(BuildContext context) {
    final Color bg = backgroundColor ?? context.colors.background;
    final ScrollPhysics? effectivePhysics =
        physics ??
        (onRefresh != null ? const AlwaysScrollableScrollPhysics() : null);
    Widget scrollView = CustomScrollView(
      controller: scrollController,
      physics: effectivePhysics,
      slivers: kasyOverlayPaddedSlivers(
        context,
        contentPadding: contentPadding,
        slivers: slivers,
      ),
    );
    final Future<void> Function()? refresh = onRefresh;
    if (refresh != null) {
      scrollView = RefreshIndicator.adaptive(
        displacement: refreshIndicatorDisplacement,
        onRefresh: refresh,
        child: scrollView,
      );
    }
    return Scaffold(
      backgroundColor: bg,
      body: Stack(
        fit: StackFit.expand,
        children: [
          Positioned.fill(child: scrollView),
          Positioned(
            top: 0,
            left: 0,
            right: 0,
            child: KasyAppBar(
              title: title,
              style: appBarStyle,
              onBack: onBack,
              onThemeToggle: onThemeToggle,
              trailing: trailing,
            ),
          ),
        ],
      ),
    );
  }
}

/// 44×44 tap target for toolbar chrome; optional [tooltip].
///
/// Calls [onPressed] on tap with no animation or delay.
class KasyAppBarChromeTap extends StatelessWidget {
  final Widget child;
  final VoidCallback onPressed;
  final String? tooltip;

  /// [Semantics.label]; defaults to `'Button'` or non-empty [tooltip].
  final String? semanticsLabel;

  const KasyAppBarChromeTap({
    super.key,
    required this.child,
    required this.onPressed,
    this.tooltip,
    this.semanticsLabel,
  });

  @override
  Widget build(BuildContext context) {
    final String tip = tooltip ?? '';
    final String label = semanticsLabel ?? (tip.isNotEmpty ? tip : 'Button');

    Widget body = Semantics(
      button: true,
      enabled: true,
      label: label,
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: onPressed,
        child: ConstrainedBox(
          constraints: const BoxConstraints(minWidth: 44, minHeight: 44),
          child: Center(child: child),
        ),
      ),
    );

    if (tip.isNotEmpty) {
      body = Tooltip(message: tip, child: body);
    }
    if (kIsWeb) {
      return MouseRegion(cursor: SystemMouseCursors.click, child: body);
    }
    return body;
  }
}

/// Circular control on the frosted toolbar (back, theme, etc.).
///
/// Wraps the orb with [KasyAppBarChromeTap] (immediate tap, no scale animation).
class KasyChromeOrbIconButton extends StatelessWidget {
  final IconData icon;
  final double iconSize;
  final Color foregroundColor;
  final VoidCallback onPressed;
  final String? tooltip;

  /// Default: [kasyChromeOrbFillColor].
  final Color? fillColor;

  const KasyChromeOrbIconButton({
    super.key,
    required this.icon,
    required this.iconSize,
    required this.foregroundColor,
    required this.onPressed,
    this.tooltip,
    this.fillColor,
  });

  @override
  Widget build(BuildContext context) {
    final bool isDark = Theme.of(context).brightness == Brightness.dark;
    final Color fill = fillColor ?? kasyChromeOrbFillColor(context);
    final double outlineAlpha = isDark ? 0.17 : 0.14;
    final BoxShadow baseShadow = KasyShadows.component(context);

    final Widget orb = Container(
      width: 44,
      height: 44,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: fill,
        border: Border.all(
          color: context.colors.outline.withValues(alpha: outlineAlpha),
        ),
        boxShadow: <BoxShadow>[
          baseShadow.copyWith(
            color: baseShadow.color.withValues(
              alpha: baseShadow.color.a * 0.42,
            ),
            blurRadius: baseShadow.blurRadius - 1.6,
          ),
        ],
      ),
      child: Center(
        child: Icon(icon, size: iconSize, color: foregroundColor),
      ),
    );

    return KasyAppBarChromeTap(
      tooltip: tooltip,
      semanticsLabel: tooltip,
      onPressed: onPressed,
      child: orb,
    );
  }
}
