// FaiErrorBox — selectable monospace error / output block with
// a small copy-to-clipboard button in the top-right corner.
//
// Used wherever the operator might want to paste daemon stderr
// into a chat or bug report: the update banner, install
// progress dialog, system-AI editor, audit-clear failures, etc.
// SelectableText alone works for keyboard users but the copy
// affordance has to be explicit so trackpad operators see it.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../data/friendly_error.dart';
import '../l10n/app_localizations.dart';
import '../theme/theme.dart';
import '../theme/tokens.dart';

class FaiErrorBox extends StatefulWidget {
  /// The text the operator wants to read (and copy). Rendered
  /// monospace, selectable, multi-line. Ignored when [error] is
  /// supplied.
  final String text;

  /// When true, the box border + foreground colour come from the
  /// error palette. False renders neutral chrome — useful for
  /// success / informational copy that still wants the copy
  /// button.
  final bool isError;

  /// Optional max-height before the content scrolls inside the
  /// box. Falls back to no constraint when null so short
  /// messages don't get a useless scrollbar.
  final double? maxHeight;

  /// When non-null, the box renders the [friendlyError] mapping
  /// of this error: a one-line headline, a recovery-hint line
  /// (when one applies), and the verbatim original message
  /// collapsed behind a "Details" expander. Use this instead of
  /// [text] anywhere we'd otherwise show a raw
  /// `e.toString()` — gRPC-Errors come out as walls of code +
  /// trailers otherwise.
  final Object? error;

  const FaiErrorBox({
    super.key,
    this.text = '',
    this.isError = false,
    this.maxHeight,
    this.error,
  }) : assert(
         text != '' || error != null,
         'FaiErrorBox needs either text or error',
       );

  @override
  State<FaiErrorBox> createState() => _FaiErrorBoxState();
}

class _FaiErrorBoxState extends State<FaiErrorBox> {
  bool _justCopied = false;
  bool _detailExpanded = false;

  Future<void> _copy(String what) async {
    await Clipboard.setData(ClipboardData(text: what));
    if (!mounted) return;
    setState(() => _justCopied = true);
    Future.delayed(const Duration(seconds: 2), () {
      if (mounted) setState(() => _justCopied = false);
    });
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final l = AppLocalizations.of(context)!;
    final accent = widget.isError
        ? theme.colorScheme.error
        : theme.colorScheme.outlineVariant;
    final fg = widget.isError
        ? theme.colorScheme.error
        : theme.colorScheme.onSurface;
    final friendly = widget.error == null
        ? null
        : friendlyError(widget.error!, l);
    final copyText = friendly?.detail ?? widget.text;
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.fromLTRB(
        FaiSpace.sm,
        FaiSpace.xs,
        FaiSpace.xs,
        FaiSpace.sm,
      ),
      decoration: BoxDecoration(
        color: theme.colorScheme.surfaceContainerHigh,
        borderRadius: BorderRadius.circular(FaiRadius.sm),
        border: Border.all(color: accent.withValues(alpha: 0.4)),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Align(
            alignment: Alignment.centerRight,
            child: Tooltip(
              message: _justCopied ? l.buttonCopied : l.buttonCopy,
              child: IconButton(
                icon: Icon(
                  _justCopied ? Icons.check : Icons.content_copy,
                  size: 14,
                ),
                visualDensity: VisualDensity.compact,
                padding: const EdgeInsets.all(4),
                constraints: const BoxConstraints(),
                onPressed: () => _copy(copyText),
              ),
            ),
          ),
          if (friendly != null) ...[
            SelectableText(
              friendly.headline,
              style: theme.textTheme.bodyMedium?.copyWith(
                color: fg,
                fontWeight: FontWeight.w600,
              ),
            ),
            if (friendly.hint != null) ...[
              const SizedBox(height: 4),
              Text(
                friendly.hint!,
                style: theme.textTheme.bodySmall?.copyWith(
                  color: theme.colorScheme.onSurfaceVariant,
                ),
              ),
            ],
            if (friendly.detail.isNotEmpty) ...[
              const SizedBox(height: FaiSpace.sm),
              InkWell(
                onTap: () => setState(() {
                  _detailExpanded = !_detailExpanded;
                }),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Icon(
                      _detailExpanded ? Icons.expand_less : Icons.expand_more,
                      size: 14,
                      color: theme.colorScheme.onSurfaceVariant,
                    ),
                    const SizedBox(width: 4),
                    Text(
                      _detailExpanded
                          ? l.buttonHideDetails
                          : l.buttonShowDetails,
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: theme.colorScheme.onSurfaceVariant,
                      ),
                    ),
                  ],
                ),
              ),
              if (_detailExpanded) ...[
                const SizedBox(height: FaiSpace.xs),
                ConstrainedBox(
                  constraints: BoxConstraints(
                    maxHeight: widget.maxHeight ?? double.infinity,
                  ),
                  child: Scrollbar(
                    child: SingleChildScrollView(
                      child: SelectableText(
                        friendly.detail,
                        style: FaiTheme.mono(
                          size: 11,
                          color: theme.colorScheme.onSurfaceVariant,
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ],
          ] else
            ConstrainedBox(
              constraints: BoxConstraints(
                maxHeight: widget.maxHeight ?? double.infinity,
              ),
              child: Scrollbar(
                child: SingleChildScrollView(
                  child: SelectableText(
                    widget.text,
                    style: FaiTheme.mono(size: 11, color: fg),
                  ),
                ),
              ),
            ),
        ],
      ),
    );
  }
}
