import 'dart:convert';

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

import '../../../core/api/api_error_mapper.dart';
import '../data/admin_repository.dart';
import '../domain/admin_ai_trace.dart';
import '../domain/admin_ai_trace_detail.dart';

class AdminAiPanel extends ConsumerStatefulWidget {
  final bool embedded;

  const AdminAiPanel({super.key, this.embedded = false});

  @override
  ConsumerState<AdminAiPanel> createState() => _AdminAiPanelState();
}

class _AdminAiPanelState extends ConsumerState<AdminAiPanel> {
  bool _isLoading = true;
  String? _error;

  AdminAiTraceSource _source = AdminAiTraceSource.flyer;
  String _period = '7d';
  bool _onlyErrors = false;

  List<AdminAiTraceListItem> _items = const [];
  String? _nextCursor;
  String? _selectedId;
  AdminAiTraceDetail? _selected;
  bool _isDetailLoading = false;
  bool _promptExpanded = false;
  String? _cachedOutputTraceId;
  String? _cachedOutputPrettyJson;

  @override
  void initState() {
    super.initState();
    _load();
  }

  Future<void> _load() async {
    setState(() {
      _isLoading = true;
      _error = null;
    });
    try {
      final response = await ref.read(adminRepositoryProvider).listAiTraces(
            source: _source,
            limit: 30,
            period: _period,
            onlyErrors: _onlyErrors,
          );
      if (!mounted) return;
      final selectedId =
          response.items.isEmpty ? null : response.items.first.id;
      setState(() {
        _items = response.items;
        _nextCursor = response.nextCursor;
        _selectedId = selectedId;
        _selected = null;
        _promptExpanded = false;
        _cachedOutputTraceId = null;
        _cachedOutputPrettyJson = null;
      });
      if (selectedId != null) {
        await _loadDetail(selectedId);
      }
    } catch (e) {
      if (!mounted) return;
      setState(() => _error = mapErrorToUserMessage(e, context));
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  Future<void> _loadMore() async {
    if (_nextCursor == null || _nextCursor!.isEmpty) return;
    try {
      final response = await ref.read(adminRepositoryProvider).listAiTraces(
            source: _source,
            limit: 30,
            cursor: _nextCursor,
            period: _period,
            onlyErrors: _onlyErrors,
          );
      if (!mounted) return;
      setState(() {
        _items = [..._items, ...response.items];
        _nextCursor = response.nextCursor;
      });
    } catch (_) {
      // Ignore soft pagination failures.
    }
  }

  Future<void> _loadDetail(String id) async {
    setState(() {
      _isDetailLoading = true;
      _selected = null;
      _cachedOutputTraceId = null;
      _cachedOutputPrettyJson = null;
    });
    try {
      final detail = await ref.read(adminRepositoryProvider).getAiTraceById(id);
      if (!mounted) return;
      setState(() => _selected = detail);
    } catch (_) {
      if (!mounted) return;
      setState(() => _selected = null);
    } finally {
      if (mounted) {
        setState(() => _isDetailLoading = false);
      }
    }
  }

  String _formatDateTime(DateTime value) {
    final local = value.toLocal();
    String two(int n) => n.toString().padLeft(2, '0');
    return '${local.year}-${two(local.month)}-${two(local.day)} ${two(local.hour)}:${two(local.minute)}';
  }

  Future<void> _copyText(String value, String label) async {
    await Clipboard.setData(ClipboardData(text: value));
    if (!mounted) return;
    ScaffoldMessenger.of(context)
        .showSnackBar(SnackBar(content: Text('$label kopierad')));
  }

  String _prettyJson(Object? data) {
    if (data == null) return '{}';
    return const JsonEncoder.withIndent('  ').convert(data);
  }

  Color _statusColor(AdminAiTraceStatus status, ColorScheme scheme) {
    return switch (status) {
      AdminAiTraceStatus.success => Colors.green.shade700,
      AdminAiTraceStatus.warning => Colors.orange.shade700,
      AdminAiTraceStatus.error => scheme.error,
    };
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) return const Center(child: CircularProgressIndicator());
    if (_error != null) {
      return buildCopyableErrorPanel(
        context: context,
        message: _error!,
        onRetry: _load,
        title: 'Kunde inte läsa AI-spårning',
      );
    }

    final content = LayoutBuilder(
      builder: (context, constraints) {
        final isWide = constraints.maxWidth >= 980;
        final listPane = _buildTraceList();
        final detailPane = _buildTraceDetail();

        if (isWide) {
          return Row(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Expanded(flex: 2, child: listPane),
              const SizedBox(width: 12),
              Expanded(flex: 3, child: detailPane),
            ],
          );
        }

        return Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            SizedBox(height: 260, child: listPane),
            const SizedBox(height: 12),
            Expanded(child: detailPane),
          ],
        );
      },
    );

    return Padding(
      padding: widget.embedded ? EdgeInsets.zero : const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          _buildTopFilters(),
          const SizedBox(height: 12),
          Expanded(child: content),
        ],
      ),
    );
  }

  Widget _buildTopFilters() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Wrap(
          spacing: 8,
          runSpacing: 8,
          crossAxisAlignment: WrapCrossAlignment.center,
          children: [
            ChoiceChip(
              label: const Text('Kvitto'),
              selected: _source == AdminAiTraceSource.receipt,
              onSelected: (_) {
                setState(() => _source = AdminAiTraceSource.receipt);
                _load();
              },
            ),
            ChoiceChip(
              label: const Text('Flyer'),
              selected: _source == AdminAiTraceSource.flyer,
              onSelected: (_) {
                setState(() => _source = AdminAiTraceSource.flyer);
                _load();
              },
            ),
            const SizedBox(width: 8),
            FilterChip(
              label: const Text('24h'),
              selected: _period == '24h',
              onSelected: (_) {
                setState(() => _period = '24h');
                _load();
              },
            ),
            FilterChip(
              label: const Text('7d'),
              selected: _period == '7d',
              onSelected: (_) {
                setState(() => _period = '7d');
                _load();
              },
            ),
            FilterChip(
              label: const Text('30d'),
              selected: _period == '30d',
              onSelected: (_) {
                setState(() => _period = '30d');
                _load();
              },
            ),
            FilterChip(
              label: const Text('Endast fel'),
              selected: _onlyErrors,
              onSelected: (value) {
                setState(() => _onlyErrors = value);
                _load();
              },
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildTraceList() {
    final theme = Theme.of(context);
    if (_items.isEmpty) {
      return Card(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Text(
            _source == AdminAiTraceSource.receipt
                ? 'Receipt trace-data saknas i recipe-api i denna fas.'
                : 'Inga importer matchar valda filter.',
            style: theme.textTheme.bodyMedium,
          ),
        ),
      );
    }

    return Card(
      child: Column(
        children: [
          Expanded(
            child: ListView.separated(
              itemCount: _items.length,
              separatorBuilder: (_, __) => const Divider(height: 1),
              itemBuilder: (context, index) {
                final item = _items[index];
                final selected = item.id == _selectedId;
                return ListTile(
                  selected: selected,
                  onTap: () {
                    setState(() {
                      _selectedId = item.id;
                      _promptExpanded = false;
                    });
                    _loadDetail(item.id);
                  },
                  title: Text(item.fileName ?? item.id),
                  subtitle: Text(
                      '${_formatDateTime(item.createdAt)}  •  ${item.userLabel}'),
                  trailing: Tooltip(
                    message: _statusTooltipText(item),
                    child: Chip(
                      label: Text(item.status.label),
                      labelStyle: TextStyle(
                          color: _statusColor(item.status, theme.colorScheme)),
                    ),
                  ),
                );
              },
            ),
          ),
          if (_nextCursor != null && _nextCursor!.isNotEmpty)
            Padding(
              padding: const EdgeInsets.all(8),
              child: OutlinedButton.icon(
                onPressed: _loadMore,
                icon: const Icon(Icons.expand_more),
                label: const Text('Ladda fler'),
              ),
            ),
        ],
      ),
    );
  }

  Widget _buildTraceDetail() {
    if (_isDetailLoading) {
      return const Card(child: Center(child: CircularProgressIndicator()));
    }
    final detail = _selected;
    if (detail == null) {
      return const Card(
        child: Center(
          child: Padding(
            padding: EdgeInsets.all(16),
            child: Text('Välj en import för detaljer.'),
          ),
        ),
      );
    }

    final prompt = detail.prompt;
    final outputJson = detail.normalizedOutput ??
        (detail.rawOutput == null
            ? const <String, dynamic>{}
            : {'rawOutput': detail.rawOutput});
    final prettyOutput = _prettyOutputFor(detail.id, outputJson);

    return ListView(
      children: [
        _TraceMetaCard(detail: detail, formatDateTime: _formatDateTime),
        if (detail.warnings.isNotEmpty) ...[
          const SizedBox(height: 12),
          _WarningsCard(
            warnings: detail.warnings,
            onCopyWarning: (warning) => _copyText(warning, 'Varning'),
            onCopyAll: () => _copyText(detail.warnings.join('\n'), 'Varningar'),
          ),
        ],
        const SizedBox(height: 12),
        _PromptCard(
          prompt: prompt,
          expanded: _promptExpanded,
          onToggleExpand: () =>
              setState(() => _promptExpanded = !_promptExpanded),
          onCopy: prompt == null ? null : () => _copyText(prompt, 'Prompt'),
        ),
        const SizedBox(height: 12),
        _OutputJsonCard(
          jsonText: prettyOutput,
          onCopy: () => _copyText(prettyOutput, 'Output JSON'),
        ),
      ],
    );
  }

  String _prettyOutputFor(String traceId, Object? outputJson) {
    if (_cachedOutputTraceId == traceId && _cachedOutputPrettyJson != null) {
      return _cachedOutputPrettyJson!;
    }
    final next = _prettyJson(outputJson);
    _cachedOutputTraceId = traceId;
    _cachedOutputPrettyJson = next;
    return next;
  }

  String _statusTooltipText(AdminAiTraceListItem item) {
    final parts = <String>[];
    if (item.status == AdminAiTraceStatus.warning && item.warningsCount > 0) {
      parts.add('${item.warningsCount} varning(ar). Välj raden för detaljer och kopiering.');
    }
    if (item.error != null && item.error!.trim().isNotEmpty) {
      parts.add(item.error!.trim());
    }
    if (parts.isEmpty) {
      return 'Inga ytterligare detaljer.';
    }
    return parts.join('\n');
  }
}

class _TraceMetaCard extends StatelessWidget {
  final AdminAiTraceDetail detail;
  final String Function(DateTime value) formatDateTime;

  const _TraceMetaCard({required this.detail, required this.formatDateTime});

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Sammanfattning', style: theme.textTheme.titleMedium),
            const SizedBox(height: 8),
            Text('Källa: ${detail.source.label}'),
            Text('Tid: ${formatDateTime(detail.createdAt)}'),
            Text('Användare: ${detail.userLabel}'),
            Text('Status: ${detail.status.label}'),
            Text('Modell: ${detail.model ?? 'okänd'}'),
            if (detail.durationMs != null)
              Text('Duration: ${detail.durationMs} ms'),
            if (detail.chunkCount != null) Text('Chunks: ${detail.chunkCount}'),
            if (detail.retryCount != null)
              Text('Retries: ${detail.retryCount}'),
            if (detail.warnings.isNotEmpty)
              Text('Warnings: ${detail.warnings.length}'),
            if (detail.error != null && detail.error!.isNotEmpty)
              Text('Fel: ${detail.error}',
                  style: TextStyle(color: theme.colorScheme.error)),
          ],
        ),
      ),
    );
  }
}

class _PromptCard extends StatelessWidget {
  final String? prompt;
  final bool expanded;
  final VoidCallback onToggleExpand;
  final VoidCallback? onCopy;

  const _PromptCard({
    required this.prompt,
    required this.expanded,
    required this.onToggleExpand,
    required this.onCopy,
  });

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final value = (prompt ?? '').trim();
    final hasPrompt = value.isNotEmpty;

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Expanded(
                    child: Text('Prompt', style: theme.textTheme.titleMedium)),
                IconButton(
                  tooltip: 'Expandera/kollapsa',
                  onPressed: hasPrompt ? onToggleExpand : null,
                  icon: Icon(expanded ? Icons.unfold_less : Icons.unfold_more),
                ),
                IconButton(
                  tooltip: 'Kopiera',
                  onPressed: hasPrompt ? onCopy : null,
                  icon: const Icon(Icons.copy_all),
                ),
              ],
            ),
            const SizedBox(height: 8),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: theme.colorScheme.surfaceContainerHighest
                    .withValues(alpha: 0.35),
                borderRadius: BorderRadius.circular(8),
              ),
              child: SelectionArea(
                child: SelectableText(
                  hasPrompt ? value : 'Prompt saknas för detta spår.',
                  maxLines: expanded ? null : 10,
                  style: theme.textTheme.bodySmall
                      ?.copyWith(fontFamily: 'monospace'),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _OutputJsonCard extends StatefulWidget {
  final String jsonText;
  final VoidCallback onCopy;

  const _OutputJsonCard({required this.jsonText, required this.onCopy});

  @override
  State<_OutputJsonCard> createState() => _OutputJsonCardState();
}

class _OutputJsonCardState extends State<_OutputJsonCard> {
  static const int _maxPreviewChars = 12000;
  bool _expanded = false;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final shouldTruncate = widget.jsonText.length > _maxPreviewChars;
    final visibleText =
        !_expanded && shouldTruncate ? '${widget.jsonText.substring(0, _maxPreviewChars)}\n…' : widget.jsonText;

    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Expanded(
                    child: Text('Model Output',
                        style: theme.textTheme.titleMedium)),
                IconButton(
                  tooltip: 'Kopiera JSON',
                  onPressed: widget.onCopy,
                  icon: const Icon(Icons.copy_all),
                ),
              ],
            ),
            if (shouldTruncate)
              Align(
                alignment: Alignment.centerRight,
                child: TextButton.icon(
                  onPressed: () => setState(() => _expanded = !_expanded),
                  icon: Icon(_expanded ? Icons.unfold_less : Icons.unfold_more),
                  label: Text(_expanded ? 'Visa mindre' : 'Visa hela outputen'),
                ),
              ),
            const SizedBox(height: 8),
            Container(
              width: double.infinity,
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: theme.colorScheme.surfaceContainerHighest
                    .withValues(alpha: 0.35),
                borderRadius: BorderRadius.circular(8),
              ),
              child: SelectionArea(
                child: SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: SelectableText(
                    visibleText,
                    style: theme.textTheme.bodySmall
                        ?.copyWith(fontFamily: 'monospace'),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _WarningsCard extends StatelessWidget {
  final List<String> warnings;
  final void Function(String warning) onCopyWarning;
  final VoidCallback onCopyAll;

  const _WarningsCard({
    required this.warnings,
    required this.onCopyWarning,
    required this.onCopyAll,
  });

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Expanded(
                  child: Text(
                    'Varningar (${warnings.length})',
                    style: theme.textTheme.titleMedium,
                  ),
                ),
                IconButton(
                  tooltip: 'Kopiera alla varningar',
                  onPressed: onCopyAll,
                  icon: const Icon(Icons.copy_all),
                ),
              ],
            ),
            const SizedBox(height: 8),
            ...warnings.map(
              (warning) => ListTile(
                dense: true,
                contentPadding: EdgeInsets.zero,
                leading: const Icon(Icons.warning_amber_rounded, size: 18),
                title: SelectableText(warning),
                trailing: IconButton(
                  tooltip: 'Kopiera varning',
                  onPressed: () => onCopyWarning(warning),
                  icon: const Icon(Icons.copy, size: 18),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
