import 'package:comunic/enums/post_kind.dart';
import 'package:comunic/enums/post_target.dart';
import 'package:comunic/enums/post_visibility_level.dart';
import 'package:comunic/helpers/posts_helper.dart';
import 'package:comunic/models/new_post.dart';
import 'package:comunic/ui/dialogs/input_url_dialog.dart';
import 'package:comunic/ui/dialogs/input_youtube_link_dialog.dart';
import 'package:comunic/ui/dialogs/new_survey_dialog.dart';
import 'package:comunic/ui/dialogs/post_visibility_picker_dialog.dart';
import 'package:comunic/ui/widgets/post_container_widget.dart';
import 'package:comunic/utils/files_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';

import '../../models/api_request.dart';
import '../../utils/log_utils.dart';
import '../../utils/ui_utils.dart';

/// Widget that allows to create posts
///
/// @author Pierre HUBERT

const _ActiveButtonsColor = Colors.blue;
const _InactiveButtonsColor = Colors.grey;

class PostCreateFormWidget extends StatefulWidget {
  final PostTarget postTarget;
  final int targetID;
  final void Function() onCreated;

  const PostCreateFormWidget({
    Key key,
    @required this.postTarget,
    @required this.targetID,
    @required this.onCreated,
  })  : assert(postTarget != null),
        assert(targetID != null),
        super(key: key);

  @override
  _PostCreateFormWidgetState createState() => _PostCreateFormWidgetState();
}

class _PostCreateFormWidgetState extends State<PostCreateFormWidget> {
  // Helpers
  final PostsHelper _postHelper = PostsHelper();

  // Class members
  bool _isCreating = false;
  final TextEditingController _postTextController = TextEditingController();
  PostVisibilityLevel _postVisibilityLevel;
  BytesFile _postImage;
  String _postURL;
  List<int> _postPDF;
  DateTime _timeEnd;
  NewSurvey _postSurvey;
  String _youtubeID;

  bool get hasImage => _postImage != null;

  bool get hasURL => _postURL != null;

  bool get hasPDF => _postPDF != null;

  bool get hasTimeEnd => _timeEnd != null;

  bool get hasSurvey => _postSurvey != null;

  bool get hasYouTubeID => _youtubeID != null;

  bool get canSubmitForm =>
      !_isCreating && _postTextController.text.length > 5 ||
      postKind != PostKind.TEXT;

  PostKind get postKind {
    if (hasImage)
      return PostKind.IMAGE;
    else if (hasPDF)
      return PostKind.PDF;
    else if (hasURL)
      return PostKind.WEB_LINK;
    else if (hasTimeEnd)
      return PostKind.COUNTDOWN;
    else if (hasSurvey)
      return PostKind.SURVEY;
    else if (hasYouTubeID)
      return PostKind.YOUTUBE;
    else
      return PostKind.TEXT;
  }

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

    _resetForm();
  }

  @override
  Widget build(BuildContext context) {
    return PostContainer(
      child: Card(
        child: Column(
          children: <Widget>[
            // Post text content
            Padding(
              padding: const EdgeInsets.only(left: 8.0, right: 8.0),
              child: TextField(
                controller: _postTextController,
                minLines: 3,
                maxLines: 10,
                decoration:
                    InputDecoration(hintText: tr("Create a new post...")),
                onChanged: (s) => setState(() {}),
              ),
            ),

            // Post options
            Padding(
              padding: const EdgeInsets.only(right: 16.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  // Text post button
                  Expanded(
                    child: SingleChildScrollView(
                      scrollDirection: Axis.horizontal,
                      child: Row(
                        children: <Widget>[
                          _PostOptionWidget(
                              icon: Icons.text_format,
                              selected: postKind == PostKind.TEXT,
                              onTap: _resetPostSelection),

                          // Include image button
                          _PostOptionWidget(
                            icon: Icons.image,
                            selected: postKind == PostKind.IMAGE,
                            onTap: _pickImageForPost,
                          ),

                          // Web link
                          _PostOptionWidget(
                            icon: Icons.link,
                            selected: postKind == PostKind.WEB_LINK,
                            onTap: _pickURLForPost,
                          ),

                          // Include PDF button
                          _PostOptionWidget(
                            icon: Icons.picture_as_pdf,
                            selected: postKind == PostKind.PDF,
                            onTap: _pickPDFForPost,
                          ),

                          // Add countdown timer
                          _PostOptionWidget(
                            icon: Icons.timer,
                            selected: postKind == PostKind.COUNTDOWN,
                            onTap: _pickCountdownTime,
                          ),

                          // Add survey
                          _PostOptionWidget(
                            icon: Icons.insert_chart,
                            selected: postKind == PostKind.SURVEY,
                            onTap: _pickSurvey,
                          ),

                          // Specify YouTube video ID
                          _PostOptionWidget(
                            icon: Icons.ondemand_video,
                            selected: postKind == PostKind.YOUTUBE,
                            onTap: _pickYouTubeVideo,
                          ),
                        ],
                      ),
                    ),
                  ),

                  Container(width: 20),

                  // Post visibility level
                  _PostOptionWidget(
                    icon: PostVisibilityLevelsMapIcons[_postVisibilityLevel],
                    selected: false,
                    customColor: Colors.black,
                    onTap: _changeVisibilityLevel,
                  ),

                  // Submit post button
                  _isCreating
                      ? Container()
                      : ElevatedButton(
                          child: Text(tr("Send").toUpperCase()),
                          onPressed: canSubmitForm ? _submitForm : null),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

  /// Reset the form
  void _resetForm() {
    setState(() {
      _postVisibilityLevel = widget.postTarget == PostTarget.GROUP_PAGE
          ? PostVisibilityLevel.GROUP_MEMBERS
          : PostVisibilityLevel.FRIENDS;

      _postTextController.text = "";
      _resetPostSelection();
    });
  }

  /// Change post visibility level
  Future<void> _changeVisibilityLevel() async {
    final newLevel = await showPostVisibilityPickerDialog(
      context: context,
      initialLevel: _postVisibilityLevel,
      isGroup: widget.postTarget == PostTarget.GROUP_PAGE,
    );

    setState(() => _postVisibilityLevel = newLevel);
  }

  /// Remove all data attached to the post (image, etc...)
  void _resetPostSelection() {
    setState(() {
      _postImage = null;
      _postURL = null;
      _postPDF = null;
      _timeEnd = null;
      _postSurvey = null;
      _youtubeID = null;
    });
  }

  /// Pick an image for the new post
  Future<void> _pickImageForPost() async {
    try {
      final image = await pickImage(context);

      if (image == null) return;

      _resetPostSelection();

      setState(() {
        this._postImage = image;
      });
    } catch (e, s) {
      logError(e, s);
      snack(context, tr("Failed to pick an image for the post!"));
    }
  }

  /// Choose a new URL for the post
  Future<void> _pickURLForPost() async {
    final url = await showInputURLDialog(
      context: context,
      title: tr("Specify URL"),
      initialURL: _postURL,
    );

    if (url == null) return;

    _resetPostSelection();

    setState(() {
      _postURL = url;
    });
  }

  /// Pick a PDF for the new post
  Future<void> _pickPDFForPost() async {
    try {
      final file = await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowedExtensions: ["pdf"],
        withData: true,
      );

      if (file == null || file.files.isEmpty) return;

      _resetPostSelection();

      setState(() {
        this._postPDF = file.files.first.bytes;
      });
    } catch (e, stack) {
      print("Pick PDF error: $e\n$stack");
      showSimpleSnack(context, tr("Could not pick a PDF!"));
    }
  }

  /// Pick countdown time
  Future<void> _pickCountdownTime() async {
    final yesterday = DateTime.now().subtract(Duration(days: 1));

    final initialDate = _timeEnd == null ? DateTime.now() : _timeEnd;

    // Pick date
    final newDate = await showDatePicker(
        context: context,
        initialDate: initialDate,
        firstDate: yesterday.isBefore(initialDate) ? yesterday : initialDate,
        lastDate: DateTime.now().add(Duration(days: 5000)));

    if (newDate == null) return;

    // Pick time
    final newTime = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.fromDateTime(initialDate),
    );

    if (newTime == null) return;

    // Apply new selection
    _resetPostSelection();
    setState(() {
      _timeEnd = newDate.add(Duration(
          hours: newTime.hour - newDate.hour,
          minutes: newTime.minute - newDate.minute,
          seconds: -newDate.second));
    });
  }

  /// Pick a new survey for this post
  Future<void> _pickSurvey() async {
    final newSurvey =
        await showNewSurveyDialog(context: context, initialSurvey: _postSurvey);

    if (newSurvey == null) return;

    _resetPostSelection();
    setState(() {
      _postSurvey = newSurvey;
    });
  }

  /// Pick a new YouTube video
  Future<void> _pickYouTubeVideo() async {
    final youtubeID = await showInputYouTubeIDDialog(context, _youtubeID);

    if (youtubeID == null) return;

    _resetPostSelection();
    setState(() {
      _youtubeID = youtubeID;
    });
  }

  /// Submit new post
  Future<void> _submitForm() async {
    if (!canSubmitForm)
      showSimpleSnack(context, tr("Form can not be submitted at this point!"));

    setState(() => _isCreating = true);

    try {
      await _postHelper.createPost(NewPost(
        target: widget.postTarget,
        targetID: widget.targetID,
        visibility: _postVisibilityLevel,
        content: _postTextController.text,
        kind: postKind,
        image: _postImage,
        url: _postURL,
        pdf: _postPDF,
        timeEnd: _timeEnd,
        survey: _postSurvey,
        youtubeId: _youtubeID,
      ));
      setState(() => _isCreating = false);

      showSimpleSnack(context, tr("The post has been successfully created!"));

      this._resetForm();
      widget.onCreated();
    } catch (e) {
      setState(() => _isCreating = false);
      print("Error while creating post : " + e.toString());
      showSimpleSnack(context, tr("Could not create post !"));
    }
  }
}

/// Widget for a single post option
class _PostOptionWidget extends StatelessWidget {
  final IconData icon;
  final bool selected;
  final Color customColor;
  final void Function() onTap;

  const _PostOptionWidget(
      {Key key,
      @required this.icon,
      @required this.selected,
      @required this.onTap,
      this.customColor})
      : assert(icon != null),
        assert(selected != null),
        assert(onTap != null),
        super(key: key);

  bool get hasCustomColor => customColor != null;

  @override
  Widget build(BuildContext context) {
    return IconButton(
      icon: Icon(icon),
      onPressed: onTap,
      color: hasCustomColor
          ? customColor
          : selected
              ? _ActiveButtonsColor
              : _InactiveButtonsColor,
    );
  }
}