import 'dart:io';

import 'package:flutter/material.dart';
import 'package:loader_overlay/loader_overlay.dart';
import 'package:nextcloud/nextcloud.dart';
import 'package:uuid/uuid.dart';

import '../../../api/marianumcloud/webdav/webdavApi.dart';
import '../../../widget/confirmDialog.dart';
import '../../../widget/focusBehaviour.dart';

class FilesUploadDialog extends StatefulWidget {
  final List<String> filePaths;
  final String remotePath;
  final void Function(List<String> uploadedFilePaths) onUploadFinished;
  final bool uniqueNames;

  const FilesUploadDialog({super.key, required this.filePaths, required this.remotePath, required this.onUploadFinished, this.uniqueNames = false});

  @override
  State<FilesUploadDialog> createState() => _FilesUploadDialogState();
}

class UploadableFile {
  TextEditingController fileNameController = TextEditingController();
  String filePath;
  String fileName;
  double? _uploadProgress;
  bool isConflicting = false;

  UploadableFile(this.filePath, this.fileName);
}


class _FilesUploadDialogState extends State<FilesUploadDialog> {
  late List<UploadableFile> _uploadableFiles;
  bool _isUploading = false;
  double _overallProgressValue = 0.0;
  String _infoText = '';

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

    _uploadableFiles = widget.filePaths.map((filePath) {
      var fileName = filePath.split(Platform.pathSeparator).last;
      return UploadableFile(filePath, fileName);
    }).toList();
  }

  void showHttpErrorCode(int httpErrorCode){
    showDialog(
      context: context,
      builder: (BuildContext context) => AlertDialog(
          title: const Text('Ein Fehler ist aufgetreten'),
          contentPadding: const EdgeInsets.all(10),
          content: Text('Error code: $httpErrorCode'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('Schließen', textAlign: TextAlign.center),
            ),
          ],
        )
    );
  }

  Future<void> uploadFiles({bool override = false}) async {
    setState(() {
      _isUploading = true;
      _infoText = 'Vorbereiten';
      for (var file in _uploadableFiles) {
        file.isConflicting = false;
      }
    });

    var webdavClient = await WebdavApi.webdav;

    if (!override) {
      var result = (await webdavClient.propfind(PathUri.parse(widget.remotePath))).responses;
      var conflictingFiles = _uploadableFiles.where((file) {
        var fileName = file.fileName;
        return result.any((element) => Uri.decodeComponent(element.href!).endsWith('/$fileName'));
      }).toList();

      if(conflictingFiles.isNotEmpty) {
        bool replaceFiles = await showDialog(
          context: context,
          barrierDismissible: false,
          builder: (context) => AlertDialog(
              contentPadding: const EdgeInsets.all(10),
              title: const Text('Konflikt', textAlign: TextAlign.center),
              content: conflictingFiles.length == 1 ?
              Text(
                'Eine Datei mit dem Namen "${conflictingFiles.map((e) => e.fileName).first}" existiert bereits.',
                textAlign: TextAlign.left,
              ) :
              SingleChildScrollView(
                child: Text(
                  '${conflictingFiles.length} Dateien mit folgenden Namen existieren bereits: \n${conflictingFiles.map((e) => '\n -  ${e.fileName}').join('')}',
                  textAlign: TextAlign.left,
                ),
              ),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(context, false);
                  },
                  child: const Text('Bearbeiten', textAlign: TextAlign.center),
                ),
                TextButton(
                  onPressed: () {
                    showDialog(
                      context: context,
                      builder: (context) => ConfirmDialog(
                        title: 'Bestätigen?',
                        content: 'Bist du sicher, dass du ${conflictingFiles.length} Dateien überschreiben möchtest?',
                        onConfirm: () {
                          Navigator.pop(context, true);
                        },
                        confirmButton: 'Ja',
                        cancelButton: 'Nein',
                        ),
                    );

                  },
                  child: const Text('Überschreiben', textAlign: TextAlign.center),
                ),
              ],
            )
        );

        if(!replaceFiles) {
          setState(() {
            _isUploading = false;
            _overallProgressValue = 0.0;
            _infoText = '';
            for (var element in conflictingFiles) {
              element.isConflicting = true;
            }
          });
          return;
        }
      }
    }

    var uploadetFilePaths = <String>[];
    for (var file in _uploadableFiles) {
      var fileName = file.fileName;
      var filePath = file.filePath;

      if(widget.uniqueNames) fileName = '${fileName.split('.').first}-${const Uuid().v4()}.${fileName.split('.').last}';

      var fullRemotePath = '${widget.remotePath}/$fileName';

      setState(() {
        _infoText = '${_uploadableFiles.indexOf(file) + 1}/${_uploadableFiles.length}';
      });

      var uploadTask = await webdavClient.putFile(
        File(filePath),
        FileStat.statSync(filePath),
        PathUri.parse(fullRemotePath),
        onProgress: (progress) {
          setState(() {
            file._uploadProgress = progress;
            _overallProgressValue = ((progress + _uploadableFiles.indexOf(file)) / _uploadableFiles.length).toDouble();
          });
        },
      );

      if(uploadTask.statusCode < 200 || uploadTask.statusCode > 299) {
        setState(() {
          _isUploading = false;
          _overallProgressValue = 0.0;
          _infoText = '';
        });
        Navigator.of(context).pop();
        showHttpErrorCode(uploadTask.statusCode);
      } else {
        uploadetFilePaths.add(fullRemotePath);
      }
    }

    setState(() {
      _isUploading = false;
      _overallProgressValue = 0.0;
      _infoText = '';
    });
    Navigator.of(context).pop();
    widget.onUploadFinished(uploadetFilePaths);
  }

  @override
  Widget build(BuildContext context) => Scaffold(
      appBar: AppBar(
        title: const Text('Dateien hochladen'),
        automaticallyImplyLeading: false,
      ),
      body: LoaderOverlay(
        overlayWholeScreen: true,
        child: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _uploadableFiles.length,
                itemBuilder: (context, index) {
                  final currentFile = _uploadableFiles[index];
                  currentFile.fileNameController.text = currentFile.fileName;
                  return ListTile(
                    title: TextField(
                      readOnly: _isUploading,
                      controller: currentFile.fileNameController,
                      decoration: InputDecoration(
                        border: const UnderlineInputBorder(),
                        label: Text('Datei ${index+1}'),
                        errorText: currentFile.isConflicting ? 'existiert bereits' : null,
                        errorStyle: const TextStyle(color: Colors.red),
                      ),
                      onChanged: (input) {
                        currentFile.fileName = input;
                      },
                      onTapOutside: (PointerDownEvent event) {
                        FocusBehaviour.textFieldTapOutside(context);
                        if(currentFile.isConflicting){
                          setState(() {
                            currentFile.isConflicting = false;
                          });
                        }
                      },
                      onEditingComplete: () {
                        if(currentFile.isConflicting){
                          setState(() {
                            currentFile.isConflicting = false;
                          });
                        }
                      },
                    ),
                    subtitle: _isUploading && (currentFile._uploadProgress ?? 0) < 1 ? LinearProgressIndicator(
                      value: currentFile._uploadProgress,
                      borderRadius: const BorderRadius.all(Radius.circular(2)),
                    ) : null,
                    trailing: Container(
                      width: 24,
                      height: 24,
                      padding: EdgeInsets.zero,
                      child: IconButton(
                        tooltip: 'Datei entfernen',
                        padding: EdgeInsets.zero,
                        onPressed: () {
                          if(!_isUploading) {
                            if(_uploadableFiles.length-1 <= 0) Navigator.of(context).pop();
                            setState(() {
                              _uploadableFiles.removeAt(index);
                            });
                          }
                        },
                        icon: const Icon(Icons.delete_outlined),
                      ),
                    ),
                  );
                },
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(left: 15, right: 15, bottom: 15, top: 5),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Visibility(
                    visible: !_isUploading,
                    child: TextButton(
                      onPressed: () => Navigator.of(context).pop(),
                      child: const Text('Abbrechen'),
                    ),
                  ),
                  const Expanded(child: SizedBox.shrink()),
                  Visibility(
                    visible: _isUploading,
                    replacement: TextButton(
                      onPressed: () => uploadFiles(override: widget.uniqueNames),
                      child: const Text('Hochladen'),
                    ),
                    child: Visibility(
                      visible: _infoText.length < 5,
                      replacement: Row(
                        children: [
                          Text(_infoText),
                          const SizedBox(width: 15),
                          CircularProgressIndicator(value: _overallProgressValue),
                        ],
                      ),
                      child: Stack(
                        alignment: Alignment.center,
                        children: [
                          CircularProgressIndicator(value: _overallProgressValue),
                          Center(child: Text(_infoText)),
                        ],
                      ),
                    ),


                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
}