import 'dart:developer';
import 'dart:io';

import 'package:async/async.dart';
import 'package:flutter/material.dart';
import 'package:nextcloud/nextcloud.dart';

import '../../../api/marianumcloud/webdav/webdavApi.dart';

class FileUploadDialog extends StatefulWidget {
  final String localPath;
  final List<String> remotePath;
  final String fileName;
  final void Function() onUploadFinished;

  final bool doShowFinish;

  const FileUploadDialog({super.key, required this.localPath, required this.remotePath, required this.fileName, required this.onUploadFinished, this.doShowFinish = true});

  @override
  State<FileUploadDialog> createState() => _FileUploadDialogState();
}

class _FileUploadDialogState extends State<FileUploadDialog> {
  FileUploadState state = FileUploadState.naming;
  CancelableOperation? cancelableOperation;
  late String targetFileName;
  late String remoteFolderName;
  late String fullRemotePath = "${widget.remotePath.join("/")}/$targetFileName";
  String? lastError;

  TextEditingController fileNameController = TextEditingController();


  void upload({bool override = false}) async {
    setState(() {
      state = FileUploadState.upload;
    });

    WebDavClient webdavClient = await WebdavApi.webdav;

    if(!override) {
      setState(() {
        state = FileUploadState.checkConflict;
      });
      List<WebDavResponse> result = (await webdavClient.propfind(PathUri.parse(widget.remotePath.join("/")))).responses;
      if(result.any((element) => element.href!.endsWith("/$targetFileName"))) {
        setState(() {
          state = FileUploadState.conflict;
        });
        return;
      } else {
        setState(() {
          state = FileUploadState.upload;
        });
      }
    }

    Future<HttpClientResponse> uploadTask = webdavClient.putFile(File(widget.localPath), FileStat.statSync(widget.localPath), PathUri.parse(fullRemotePath)); // TODO use onProgress from putFile
    uploadTask.then((value) => Future<HttpClientResponse?>.value(value)).catchError((e) {
      setState(() {
        state = FileUploadState.error;
      });
      return null;
    });


    cancelableOperation = CancelableOperation<HttpClientResponse>.fromFuture(
      uploadTask,
      onCancel: () => log("Upload cancelled"),
    );

    cancelableOperation!.then((value) {
      setState(() {
        state = FileUploadState.done;
      });
    });
  }

  void cancel() {
    cancelableOperation?.cancel();
    setState(() {
      state = FileUploadState.naming;
    });
  }
  
  @override
  void initState() {
    super.initState();
    targetFileName = widget.fileName;
    remoteFolderName = widget.remotePath.isNotEmpty ? widget.remotePath.last : "/";
    fileNameController.text = widget.fileName;
  }
  
  @override
  Widget build(BuildContext context) {
    if(state == FileUploadState.naming) {
      return AlertDialog(
        title: const Text("Datei hochladen"),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextField(
              controller: fileNameController,
              onChanged: (input) {
                targetFileName = input;
              },
              autocorrect: false,
              decoration: const InputDecoration(
                labelText: "Dateiname",
              ),
            ),
          ],
        ),
        actions: [
          TextButton(onPressed: () {
            Navigator.of(context).pop();
          }, child: const Text("Abbrechen")),
          TextButton(onPressed: () async {
            upload();
          }, child: const Text("Hochladen")),
        ],

      );
    }

    if(state == FileUploadState.conflict) {
      return AlertDialog(
        icon: const Icon(Icons.error_outline),
        title: const Text("Datei konflikt"),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text("Es gibt bereits eine Datei mit dem Namen $targetFileName in dem ausgewählten Ordner '$remoteFolderName'", textAlign: TextAlign.center),
          ],
        ),
        actions: [
          TextButton(onPressed: () {
            setState(() {
              state = FileUploadState.naming;
            });
          }, child: const Text("Datei umbenennen")),
          TextButton(onPressed: () {
            upload(override: true);
          }, child: const Text("Datei überschreiben")),
        ],

      );
    }

    if(state == FileUploadState.upload || state == FileUploadState.checkConflict) {
      return AlertDialog(
        icon: const Icon(Icons.upload),
        title: const Text("Hochladen"),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Visibility(
              visible: state == FileUploadState.upload,
              replacement: const Text("Prüfe auf dateikonflikte..."),
              child: const Text("Upload läuft!\nDies kann je nach Dateigröße einige Zeit dauern...", textAlign: TextAlign.center),
            ),
            const SizedBox(height: 30),
            const CircularProgressIndicator()
          ],
        ),
        actions: const [
          // TODO implement working upload cancelling
          // TextButton(onPressed: () {
          //   cancel();
          // }, child: const Text("Abbrechen")),
        ],

      );
    }

    if(state == FileUploadState.done) {
      widget.onUploadFinished();
      if(!widget.doShowFinish) {
        Navigator.of(context).pop();
        return const SizedBox.shrink();
      }
      return AlertDialog(
        icon: const Icon(Icons.done),
        title: const Text("Upload fertig"),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text("Die Datei wurde erfolgreich nach '$remoteFolderName' hochgeladen!", textAlign: TextAlign.center),
          ],
        ),
        actions: [
          TextButton(onPressed: () {
            Navigator.of(context).pop();
          }, child: const Text("Fertig")),
        ],

      );
    }

    if(state == FileUploadState.error) {
      return AlertDialog(
        icon: const Icon(Icons.error_outline),
        title: const Text("Fehler"),
        content: const Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text("Es ist ein Fehler aufgetreten!", textAlign: TextAlign.center),
          ],
        ),
        actions: [
          TextButton(onPressed: () {
            Navigator.of(context).pop();
          }, child: const Text("Schlißen")),
        ],

      );
    }

    throw UnimplementedError("Invalid state");

  }
}

enum FileUploadState {
  naming,
  checkConflict,
  conflict,
  upload,
  done,
  error
}