import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:file_picker/file_picker.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import '../models/attachment_file.dart';
import '../../core/i18n/app_localizations.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_colors_extension.dart';

// ═══════════════════════════════════════════════════════════════
// Controller
// ═══════════════════════════════════════════════════════════════

class AttachmentPickerController extends ChangeNotifier {
  final int maxCount;

  final List<AttachmentFile> _files = [];
  List<AttachmentFile> get files => List.unmodifiable(_files);
  int get count => _files.length;
  bool get isFull => _files.length >= maxCount;

  AttachmentPickerController({
    this.maxCount = 9,
    List<AttachmentFile>? initialFiles,
  }) {
    if (initialFiles != null) {
      _files.addAll(initialFiles.take(maxCount));
    }
  }

  void addFile(AttachmentFile file) {
    if (_files.length >= maxCount) return;
    _files.add(file);
    notifyListeners();
  }

  void addFiles(List<AttachmentFile> files) {
    for (final f in files) {
      if (_files.length >= maxCount) break;
      _files.add(f);
    }
    notifyListeners();
  }

  void removeFile(int index) {
    if (index < 0 || index >= _files.length) return;
    _files.removeAt(index);
    notifyListeners();
  }

  void clear() {
    if (_files.isEmpty) return;
    _files.clear();
    notifyListeners();
  }

  /// 从路径列表恢复（草稿兼容）
  Future<void> restoreFromPaths(List<String> paths) async {
    _files.clear();
    for (final path in paths.take(maxCount)) {
      _files.add(await AttachmentFile.fromPath(path));
    }
    notifyListeners();
  }

  /// 导出为路径列表（草稿持久化）
  List<String> toPathList() => _files.map((f) => f.path).toList();
}

// ═══════════════════════════════════════════════════════════════
// Widget
// ═══════════════════════════════════════════════════════════════

class AttachmentPicker extends StatefulWidget {
  final AttachmentPickerController controller;

  /// 图片大小上限（MB），null 不限制
  final double? maxImageSizeMB;

  /// 文件大小上限（MB），null 不限制
  final double? maxFileSizeMB;

  /// 允许的文件扩展名，null 使用默认 pdf/doc/docx/xls/xlsx/ppt/pptx/txt
  final List<String>? allowedExtensions;

  /// 文件被拒时回调
  final void Function(AttachmentFile file, String reason)? onFileRejected;

  /// 缩略图尺寸
  final double thumbnailSize;

  const AttachmentPicker({
    super.key,
    required this.controller,
    this.maxImageSizeMB,
    this.maxFileSizeMB,
    this.allowedExtensions,
    this.onFileRejected,
    this.thumbnailSize = 80,
  });

  @override
  State<AttachmentPicker> createState() => _AttachmentPickerState();
}

class _AttachmentPickerState extends State<AttachmentPicker> {
  List<AttachmentFile> get _files => widget.controller.files;

  @override
  void initState() {
    super.initState();
    widget.controller.addListener(_onChanged);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_onChanged);
    super.dispose();
  }

  void _onChanged() {
    if (mounted) setState(() {});
  }

  // ── 选择入口 ──

  Future<void> _showPicker() async {
    _unfocus();
    final l10n = AppLocalizations.of(context);
    final colors = Theme.of(context).extension<AppColorsExtension>()!;

    final choice = await showModalBottomSheet<String>(
      context: context,
      backgroundColor: colors.bgCard,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
      ),
      builder: (ctx) => SafeArea(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              leading: const Icon(Icons.image_outlined),
              title: Text(l10n.get('pickImage')),
              onTap: () => Navigator.pop(ctx, 'image'),
            ),
            ListTile(
              leading: const Icon(Icons.description_outlined),
              title: Text(l10n.get('pickFile')),
              onTap: () => Navigator.pop(ctx, 'file'),
            ),
          ],
        ),
      ),
    );

    if (!mounted || choice == null) return;
    if (choice == 'image') {
      await _pickImages();
    } else {
      await _pickDocuments();
    }
  }

  Future<void> _pickImages() async {
    final available = widget.controller.maxCount - widget.controller.count;
    if (available <= 0) return;
    final picker = ImagePicker();
    final images = await picker.pickMultiImage(limit: available);
    if (!mounted || images.isEmpty) return;
    for (final img in images) {
      if (widget.controller.isFull) break;
      final file = await AttachmentFile.fromXFile(img);
      if (_checkOversized(file)) continue;
      widget.controller.addFile(file);
    }
  }

  Future<void> _pickDocuments() async {
    final available = widget.controller.maxCount - widget.controller.count;
    if (available <= 0) return;
    final result = await FilePicker.pickFiles(
      type: FileType.custom,
      allowedExtensions: widget.allowedExtensions ??
          const ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt'],
      allowMultiple: true,
    );
    if (!mounted || result == null || result.files.isEmpty) return;
    for (final pf in result.files) {
      if (widget.controller.isFull) break;
      if (pf.path == null) continue;
      final file = AttachmentFile.fromPlatformFile(pf);
      if (_checkOversized(file)) continue;
      widget.controller.addFile(file);
    }
  }

  /// 返回 true 表示文件超过大小限制
  bool _checkOversized(AttachmentFile file) {
    final l10n = AppLocalizations.of(context);
    final sizeMB = file.sizeMB;

    if (file.isImage && widget.maxImageSizeMB != null && sizeMB > widget.maxImageSizeMB!) {
      final reason = l10n.getString('imageSizeLimit', args: {'max': widget.maxImageSizeMB!.toStringAsFixed(0)});
      widget.onFileRejected?.call(file, reason);
      if (mounted) TDToast.showText(reason, context: context);
      return true;
    }
    if (!file.isImage && widget.maxFileSizeMB != null && sizeMB > widget.maxFileSizeMB!) {
      final reason = l10n.getString('fileSizeLimit', args: {'max': widget.maxFileSizeMB!.toStringAsFixed(0)});
      widget.onFileRejected?.call(file, reason);
      if (mounted) TDToast.showText(reason, context: context);
      return true;
    }
    return false;
  }

  void _unfocus() => FocusScope.of(context).unfocus();

  // ── UI ──

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            ..._files.asMap().entries.map(
              (e) => Stack(
                clipBehavior: Clip.none,
                children: [
                  _buildThumbnail(e.value),
                  Positioned(
                    right: -4,
                    top: -4,
                    child: GestureDetector(
                      onTap: () => widget.controller.removeFile(e.key),
                      child: Container(
                        width: 20,
                        height: 20,
                        decoration: BoxDecoration(
                          color: colors.danger,
                          shape: BoxShape.circle,
                        ),
                        child: const Icon(
                          Icons.close,
                          size: 12,
                          color: Colors.white,
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
            if (!widget.controller.isFull)
              GestureDetector(
                onTap: () => _showPicker(),
                child: Container(
                  width: widget.thumbnailSize,
                  height: widget.thumbnailSize,
                  decoration: BoxDecoration(
                    color: colors.bgPage,
                    borderRadius: BorderRadius.circular(4),
                    border: Border.all(color: colors.border, width: 1),
                  ),
                  child: Center(
                    child: Icon(
                      Icons.add,
                      size: 24,
                      color: colors.textPlaceholder,
                    ),
                  ),
                ),
              ),
          ],
        ),
      ],
    );
  }

  Widget _buildThumbnail(AttachmentFile file) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    final size = widget.thumbnailSize;

    if (file.isImage) {
      return Container(
        width: size,
        height: size,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(4),
          border: Border.all(color: colors.border, width: 0.5),
        ),
        child: ClipRRect(
          borderRadius: BorderRadius.circular(4),
          child: Image.file(
            File(file.path),
            width: size,
            height: size,
            fit: BoxFit.cover,
            errorBuilder: (_, _, _) => _buildDocTile(file, colors, size),
          ),
        ),
      );
    }

    return _buildDocTile(file, colors, size);
  }

  Widget _buildDocTile(AttachmentFile file, AppColorsExtension colors, double size) {
    return SizedBox(
      width: size,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            width: size,
            height: size,
            decoration: BoxDecoration(
              color: colors.primaryLight,
              borderRadius: BorderRadius.circular(4),
            ),
            child: Center(
              child: Icon(
                _fileTypeIcon(file.extension),
                color: colors.primary,
                size: size * 0.4,
              ),
            ),
          ),
          const SizedBox(height: 4),
          SizedBox(
            width: size,
            height: 16,
            child: _MarqueeText(
              text: file.name,
              style: TextStyle(
                fontSize: AppFontSizes.caption,
                color: colors.textSecondary,
              ),
            ),
          ),
        ],
      ),
    );
  }

  IconData _fileTypeIcon(String ext) {
    switch (ext) {
      case 'pdf':
        return Icons.picture_as_pdf;
      case 'doc':
      case 'docx':
        return Icons.description;
      case 'xls':
      case 'xlsx':
        return Icons.table_chart;
      case 'ppt':
      case 'pptx':
        return Icons.slideshow;
      default:
        return Icons.insert_drive_file;
    }
  }
}

// ═══════════════════════════════════════════════════════════════
// Marquee Text
// ═══════════════════════════════════════════════════════════════

class _MarqueeText extends StatefulWidget {
  final String text;
  final TextStyle style;
  const _MarqueeText({required this.text, required this.style});

  @override
  State<_MarqueeText> createState() => _MarqueeTextState();
}

class _MarqueeTextState extends State<_MarqueeText>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  final ScrollController _scrollController = ScrollController();
  bool _needsScroll = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 3000),
    );
    WidgetsBinding.instance.addPostFrameCallback(_measure);
  }

  void _measure(_) {
    if (!mounted || !_scrollController.hasClients) return;
    if (_scrollController.position.maxScrollExtent > 0) {
      setState(() => _needsScroll = true);
      _controller.addListener(_onScroll);
      _controller.repeat(reverse: true);
    }
  }

  void _onScroll() {
    if (!_scrollController.hasClients) return;
    final max = _scrollController.position.maxScrollExtent;
    if (max > 0) {
      _scrollController.jumpTo(_controller.value * max);
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      controller: _scrollController,
      scrollDirection: Axis.horizontal,
      physics: _needsScroll
          ? const NeverScrollableScrollPhysics()
          : const ClampingScrollPhysics(),
      child: Text(widget.text, style: widget.style, maxLines: 1),
    );
  }
}
