import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:kasy_kit/components/components.dart';
import 'package:kasy_kit/core/theme/theme.dart';
import 'package:kasy_kit/core/widgets/kasy_scroll_behavior.dart';
import 'package:kasy_kit/features/llm_chat/providers/llm_chat_notifier.dart';
import 'package:kasy_kit/features/llm_chat/ui/widgets/llm_chat_avatars.dart';
import 'package:kasy_kit/features/llm_chat/ui/widgets/llm_chat_composer.dart';
import 'package:kasy_kit/i18n/translations.g.dart';

class LlmChatPage extends ConsumerStatefulWidget {
  const LlmChatPage({super.key});

  @override
  ConsumerState<LlmChatPage> createState() => _LlmChatPageState();
}

class _LlmChatPageState extends ConsumerState<LlmChatPage> {
  final TextEditingController _controller = TextEditingController();
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    // Scroll to bottom once the history finishes loading.
    WidgetsBinding.instance.addPostFrameCallback((_) => _scrollToBottom());
  }

  void _sendMessage() {
    final prompt = _controller.text.trim();
    if (prompt.isEmpty || prompt.length > kLlmChatMaxMessageLength) return;
    _controller.clear();
    ref.read(llmChatNotifierProvider.notifier).sendMessage(prompt);
  }

  void _scrollToBottom() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!_scrollController.hasClients) return;
      _scrollController.animateTo(
        _scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 250),
        curve: Curves.easeOut,
      );
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // Scroll to bottom whenever the message list changes.
    ref.listen(llmChatNotifierProvider, (_, _) => _scrollToBottom());

    final chatAsync = ref.watch(llmChatNotifierProvider);

    return Scaffold(
      backgroundColor: context.colors.background,
      body: Stack(
        fit: StackFit.expand,
        children: [
          Positioned.fill(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Expanded(
                  child: chatAsync.when(
                    loading: () =>
                        const Center(child: CircularProgressIndicator()),
                    error: (_, _) =>
                        Center(child: Text(t.llm_chat.error_network)),
                    data: (chatState) => _buildBody(context, chatState),
                  ),
                ),
              ],
            ),
          ),
          Positioned(
            top: 0,
            left: 0,
            right: 0,
            child: KasyAppBar(
              title: t.llm_chat.title,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildBody(BuildContext context, LlmChatState chatState) {
    final messages = chatState.messages;
    final isReplying = chatState.isReplying;

    // Show the typing indicator only while waiting for the first SSE chunk.
    // Once streaming starts the partial assistant bubble is already in [messages].
    final showTypingIndicator = isReplying && !chatState.streamingStarted;

    return Column(
      children: [
        Expanded(
          child: messages.isEmpty && !isReplying
              ? _EmptyState()
              : ScrollConfiguration(
                  behavior: const KasyKitScrollBehavior(),
                  child: ListView.builder(
                    controller: _scrollController,
                    padding: EdgeInsets.fromLTRB(
                      KasySpacing.pageHorizontalGutter,
                      kasyAppBarBodyTopOverlap(context) +
                          KasySpacing.belowChromeContentGap,
                      KasySpacing.pageHorizontalGutter,
                      KasySpacing.md,
                    ),
                    // +1 for the typing indicator shown before the first SSE chunk
                    itemCount:
                        messages.length + (showTypingIndicator ? 1 : 0),
                    itemBuilder: (context, index) {
                      if (showTypingIndicator && index == messages.length) {
                        return const _TypingIndicatorRow();
                      }
                      final message = messages[index];
                      return _ChatBubble(
                        message: message,
                        isUser: message.role == 'user',
                      );
                    },
                  ),
                ),
        ),
        SafeArea(
          top: false,
          child: Padding(
            padding: const EdgeInsets.fromLTRB(
              KasySpacing.pageHorizontalGutter,
              KasySpacing.sm,
              KasySpacing.pageHorizontalGutter,
              KasySpacing.md,
            ),
            child: LlmChatComposer(
              controller: _controller,
              isReplying: isReplying,
              onSend: _sendMessage,
            ),
          ),
        ),
      ],
    );
  }
}

class _EmptyState extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.symmetric(
          horizontal: KasySpacing.pageHorizontalGutter,
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const LlmChatAssistantAvatar(
              diameter: kLlmChatEmptyAvatarDiameter,
              showShadow: true,
            ),
            const SizedBox(height: KasySpacing.md),
            Text(
              t.home.cards.assistant_title,
              textAlign: TextAlign.center,
              style: context.textTheme.titleMedium?.copyWith(
                fontWeight: FontWeight.w600,
                color: context.colors.onBackground,
              ),
            ),
            const SizedBox(height: KasySpacing.xs),
            Text(
              t.llm_chat.empty_state,
              textAlign: TextAlign.center,
              style: context.textTheme.bodyLarge?.copyWith(
                color: context.colors.muted,
                height: 1.4,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _ChatBubble extends StatelessWidget {
  const _ChatBubble({required this.message, required this.isUser});

  final ChatMessage message;
  final bool isUser;

  @override
  Widget build(BuildContext context) {
    final Widget bubble = Container(
      padding: const EdgeInsets.symmetric(
        horizontal: KasySpacing.smd,
        vertical: KasySpacing.sm,
      ),
      decoration: BoxDecoration(
        color: isUser
            ? context.colors.primary
            : context.colors.onBackground.withValues(alpha: 0.06),
        borderRadius: BorderRadius.only(
          topLeft: const Radius.circular(16),
          topRight: const Radius.circular(16),
          bottomLeft:
              isUser ? const Radius.circular(16) : const Radius.circular(4),
          bottomRight:
              isUser ? const Radius.circular(4) : const Radius.circular(16),
        ),
      ),
      child: Text(
        message.content,
        style: context.textTheme.bodyMedium?.copyWith(
          color:
              isUser ? context.colors.onPrimary : context.colors.onBackground,
          height: 1.4,
        ),
      ),
    );

    if (isUser) {
      return Padding(
        padding: const EdgeInsets.only(bottom: KasySpacing.sm),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Flexible(child: bubble),
            const SizedBox(width: KasySpacing.xs),
            const LlmChatUserAvatar(),
          ],
        ),
      );
    }

    return Padding(
      padding: const EdgeInsets.only(bottom: KasySpacing.sm),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const LlmChatAssistantAvatar(),
          const SizedBox(width: KasySpacing.xs),
          Flexible(child: bubble),
        ],
      ),
    );
  }
}

class _TypingIndicatorRow extends StatelessWidget {
  const _TypingIndicatorRow();

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.only(bottom: KasySpacing.sm),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          LlmChatAssistantAvatar(),
          SizedBox(width: KasySpacing.xs),
          _TypingIndicator(),
        ],
      ),
    );
  }
}

/// Animated three-dot indicator shown while the assistant is generating a reply.
class _TypingIndicator extends StatefulWidget {
  const _TypingIndicator();

  @override
  State<_TypingIndicator> createState() => _TypingIndicatorState();
}

class _TypingIndicatorState extends State<_TypingIndicator>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 900),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: KasySpacing.smd,
        vertical: KasySpacing.sm,
      ),
      decoration: BoxDecoration(
        color: context.colors.onBackground.withValues(alpha: 0.06),
        borderRadius: const BorderRadius.only(
          topLeft: Radius.circular(16),
          topRight: Radius.circular(16),
          bottomLeft: Radius.circular(4),
          bottomRight: Radius.circular(16),
        ),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        spacing: 4,
        children: List.generate(3, (i) {
          return AnimatedBuilder(
            animation: _controller,
            builder: (context, _) {
              // Each dot bounces at a slightly different phase.
              final double phase =
                  (_controller.value - i * 0.2).clamp(0.0, 1.0);
              final double scale = 1.0 +
                  0.4 * (phase < 0.5 ? phase * 2 : (1.0 - phase) * 2);
              return Transform.scale(
                scale: scale,
                child: Container(
                  width: 6,
                  height: 6,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: context.colors.muted,
                  ),
                ),
              );
            },
          );
        }),
      ),
    );
  }
}
