import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Lista de Tarefas',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // A tela inicial é a de login
      home: LoginScreen(),
    );
  }
}

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  bool _isLoading = false;
  Future<void> _login() async {
    setState(() {
      _isLoading = true;
    });

    final response = await http.post(
      Uri.parse('https://barra.cos.ufrj.br:443/rest/rpc/fazer_login'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'email': _emailController.text,
        'senha': _passwordController.text,
      }),
    );

    if (response.statusCode == 200) {
      final token = jsonDecode(response.body)['token'];
      Navigator.of(context).pushReplacement(
        MaterialPageRoute(
          builder: (context) =>
              TodoApp(token: token, email: _emailController.text),
        ),
      );
    } else {
      final error = jsonDecode(response.body)['message'];
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: $error')),
      );
    }

    setState(() {
      _isLoading = false;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'Senha'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            if (_isLoading)
              CircularProgressIndicator()
            else
              ElevatedButton(
                onPressed: _login,
                child: Text('Login'),
              ),
            TextButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => CadastroScreen()),
                );
              },
              child: Text('Ainda não tem uma conta? Cadastre-se'),
            ),
          ],
        ),
      ),
    );
  }
}

class CadastroScreen extends StatefulWidget {
  @override
  _CadastroScreenState createState() => _CadastroScreenState();
}

class _CadastroScreenState extends State<CadastroScreen> {
  final TextEditingController _nomeController = TextEditingController();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _celularController = TextEditingController();
  final TextEditingController _senhaController = TextEditingController();
  final TextEditingController _confirmaSenhaController =
      TextEditingController();
  bool _isLoading = false;

  Future<void> _register() async {
    if (_senhaController.text != _confirmaSenhaController.text) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('As senhas não coincidem!')),
      );
      return;
    }

    setState(() {
      _isLoading = true;
    });

    final response = await http.post(
      Uri.parse('https://barra.cos.ufrj.br:443/rest/rpc/registra_usuario'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'nome': _nomeController.text,
        'email': _emailController.text,
        'celular': _celularController.text,
        'senha': _senhaController.text,
      }),
    );

    if (response.statusCode == 200) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Sucesso ao cadastrar!')),
      );

      // Fazer login imediatamente após o cadastro
      final loginResponse = await http.post(
        Uri.parse('https://barra.cos.ufrj.br:443/rest/rpc/fazer_login'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({
          'email': _emailController.text,
          'senha': _senhaController.text,
        }),
      );

      if (loginResponse.statusCode == 200) {
        final token = jsonDecode(loginResponse.body)['token'];

        // Enviar requisição POST para /tarefas com o email e um valor vazio
        final tarefasResponse = await http.post(
          Uri.parse('https://barra.cos.ufrj.br:443/rest/tarefas'),
          headers: {
            'Authorization': 'Bearer $token',
            'Content-Type': 'application/json',
          },
          body: jsonEncode({
            'email': _emailController.text,
            'valor': [],
          }),
        );

        if (tarefasResponse.statusCode == 201) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Tarefas inicializadas com sucesso!')),
          );
        } else {
          final error = jsonDecode(tarefasResponse.body)['message'];
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Erro ao inicializar as tarefas: $error')),
          );
        }

        // Redirecionar para a tela de login
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(
            builder: (context) => LoginScreen(),
          ),
        );
      } else {
        final error = jsonDecode(loginResponse.body)['message'];
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Erro ao fazer login: $error')),
        );
      }
    } else {
      final error = jsonDecode(response.body)['message'];
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: $error')),
      );
    }

    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Cadastro'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _nomeController,
              decoration: InputDecoration(labelText: 'Nome Completo'),
            ),
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: _celularController,
              decoration: InputDecoration(labelText: 'Celular'),
            ),
            TextField(
              controller: _senhaController,
              decoration: InputDecoration(labelText: 'Senha'),
              obscureText: true,
            ),
            TextField(
              controller: _confirmaSenhaController,
              decoration: InputDecoration(labelText: 'Confirmar Senha'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            if (_isLoading)
              CircularProgressIndicator()
            else
              ElevatedButton(
                onPressed: _register,
                child: Text('Cadastrar'),
              ),
            TextButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Já tem uma conta? Faça login'),
            ),
          ],
        ),
      ),
    );
  }
}

class TodoApp extends StatefulWidget {
  final String email;
  final String token;

  // Adicionando os parâmetros no construtor
  TodoApp({required this.email, required this.token});

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

class _TodoAppState extends State<TodoApp> {
  late String _token;
  late String _email;
  List<TodoItem> _tasks = []; // Lista de tarefas

  @override
  void initState() {
    super.initState();
    _token = widget.token;
    _email = widget.email;
    _fetchTasks(); // Fazendo a requisição ao carregar a tela
  }

  Future<void> _fetchTasks() async {
    final response = await http.get(
      Uri.parse('https://barra.cos.ufrj.br:443/rest/tarefas'),
      headers: {
        'Authorization': 'Bearer ${widget.token}',
        'Content-Type': 'application/json',
      },
    );

    if (response.statusCode == 200) {
      // O JSON será salvo
      final tasksJson = jsonDecode(response.body);
      final tasks = tasksJson[0]['valor'] as List; // Acessando o campo 'valor'

      // Adicionando as tarefas na lista
      setState(() {
        _tasks = tasks.map((task) {
          return TodoItem(
            task['titulo'],
            completed: task['concluida'] ?? false,
          );
        }).toList();
      });
    } else {
      // Se falhar, mostre um erro
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro ao carregar as tarefas.')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TodoList(tasks: _tasks, email: _email, token: _token),
    );
  }
}

class TodoItem {
  String task;
  bool completed;
  bool isDeleting;

  TodoItem(this.task, {this.completed = false, this.isDeleting = false});
}

class TodoList extends StatefulWidget {
  final List<TodoItem> tasks; // Recebendo a lista de tarefas
  final String email;
  final String token;

  TodoList({required this.tasks, required this.email, required this.token});

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

class _TodoListState extends State<TodoList>
    with SingleTickerProviderStateMixin {
  List<TodoItem> get _tasks => widget.tasks; // Acessando as tarefas passadas

  // Chave para o AnimatedList
  final GlobalKey<AnimatedListState> _listKey = GlobalKey<AnimatedListState>();

  // Variáveis para a animação
  bool isAnimating = false;
  late AnimationController _animationController;
  late Animation<double> _animation;
  TodoItem? animatedTask;
  int oldIndex = -1;
  int newIndex = -1;
  double itemHeight = 0.0;

  // Mapear cada item a uma GlobalKey para obter sua posição
  final Map<TodoItem, GlobalKey> itemKeys = {};

  // Função para salvar as tarefas
  Future<void> _saveTasks() async {
    final tasksJson = _tasks.map((task) {
      return {
        'titulo': task.task,
        'concluida': task.completed,
        'ordem': _tasks.indexOf(task) + 1,
      };
    }).toList();

    final body = jsonEncode({
      'email': widget.email,
      'valor': tasksJson,
    });

    try {
      final response = await http.patch(
        Uri.parse('https://barra.cos.ufrj.br:443/rest/tarefas'),
        headers: {
          'Authorization': 'Bearer ${widget.token}',
          'Content-Type': 'application/json',
        },
        body: body,
      );
      if (response.statusCode == 204) {
        // Se a requisição for bem-sucedida
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Tarefas salvas com sucesso!')),
        );
      } else if (response.headers['content-type']
              ?.contains('application/json') ==
          true) {
        final Map<String, dynamic> responseBody = json.decode(response.body);

        // Verifica se a resposta tem a mensagem "JWT expired"
        if (responseBody['message'] == 'JWT expired') {
          // Token expirado, redireciona para LoginScreen
          Navigator.pushReplacement(
            context,
            MaterialPageRoute(builder: (context) => LoginScreen()),
          );

          // Exibe a mensagem de "Sessão Expirada"
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Sessão Expirada')),
          );
          return;
        } else {
          // Caso haja erro, exibe o código HTTP e a resposta do corpo
          print(
              "Erro ao salvar tarefas. Status Code: ${response.statusCode}");
          print("Resposta: ${response.body}");
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Erro ao salvar as tarefas.')),
          );
        }
      } else {
        // Caso haja erro, exibe o código HTTP e a resposta do corpo
        print("Erro ao salvar tarefas. Status Code: ${response.statusCode}");
        print("Resposta: ${response.body}");
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Erro ao salvar as tarefas.')),
        );
      }
    } catch (e) {
      // Em caso de exceção durante a requisição
      print("Erro na requisição: $body, $e");
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro ao salvar as tarefas.')),
      );
    }
  }

  final TextEditingController _controller = TextEditingController();
  int _deletingIndex = -1;
  bool _undoAvailable = false;

  @override
  void initState() {
    super.initState();
    // Inicializa o AnimationController
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500),
    );

    _animationController.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        // Animação concluída, atualizar a lista
        setState(() {
          isAnimating = false;
          // Remover do oldIndex
          _tasks.removeAt(oldIndex);
          _listKey.currentState?.removeItem(
            oldIndex,
            (context, animation) => SizedBox(), // Remover silenciosamente
            duration: Duration(milliseconds: 0),
          );
          // Inserir no newIndex
          _tasks.insert(newIndex, animatedTask!);
          _listKey.currentState?.insertItem(newIndex);
          // Reatribuir a chave à tarefa na nova posição
          itemKeys[animatedTask!] = GlobalKey();
        });
      }
    });
  }

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

  void _addTask(String task) {
    if (task.trim().isEmpty || _tasks.any((t) => t.task == task.trim()))
      return;
    setState(() {
      final newTask = TodoItem(task.trim());
      _tasks.insert(0, newTask);
      itemKeys[newTask] = GlobalKey();
      _listKey.currentState?.insertItem(0);
    });
    _controller.clear();
  }

  void _markForDeletion(int index) {
    setState(() {
      _tasks[index].isDeleting = true;
      _deletingIndex = index;
      _undoAvailable = true;
    });

    Future.delayed(Duration(seconds: 3), () {
      if (_undoAvailable && _deletingIndex == index) {
        _deleteTask();
      }
    });
  }

  void _deleteTask() {
    setState(() {
      if (_deletingIndex >= 0 && _deletingIndex < _tasks.length) {
        final removedTask = _tasks.removeAt(_deletingIndex);
        itemKeys.remove(removedTask);
        _listKey.currentState?.removeItem(
          _deletingIndex,
          (context, animation) => _buildRemovedItem(removedTask, animation),
        );
        _deletingIndex = -1;
        _undoAvailable = false;
      }
    });
  }

  void _undoDelete() {
    setState(() {
      _tasks[_deletingIndex].isDeleting = false;
      _deletingIndex = -1;
      _undoAvailable = false;
    });
  }

  void _toggleComplete(int index) async {
    if (isAnimating) return; // Evita iniciar múltiplas animações

    setState(() {
      isAnimating = true;
    });

    final task = _tasks[index];
    animatedTask = task;
    oldIndex = index;

    task.completed = !task.completed;

    if (task.completed) {
      // Inserir no topo das tarefas concluídas
      int firstCompletedIndex =
          _tasks.indexWhere((t) => t.completed && t != task);
      if (firstCompletedIndex == -1) {
        // Não há outras tarefas concluídas, inserir no final
        newIndex = _tasks.length - 1;
      } else {
        // Inserir na posição do primeiro concluído
        newIndex = firstCompletedIndex - 1;
      }
    } else {
      // Inserir no final das tarefas não concluídas
      int lastUncompletedIndex =
          _tasks.lastIndexWhere((t) => !t.completed && t != task);
      if (lastUncompletedIndex == -1) {
        newIndex = 0;
      } else {
        newIndex = lastUncompletedIndex + 1;
      }
    }

    // Preparar a animação
    final oldKey = itemKeys[task]!;
    final oldContext = oldKey.currentContext;
    if (oldContext == null) {
      setState(() {
        isAnimating = false;
      });
      return;
    }
    final box = oldContext.findRenderObject() as RenderBox;
    final oldPosition = box.localToGlobal(Offset.zero);
    final listBox = _listKey.currentContext!.findRenderObject() as RenderBox;
    final listPosition = listBox.localToGlobal(Offset.zero);

    final oldOffset = oldPosition.dy - listPosition.dy;

    itemHeight = box.size.height;

    final newOffset = itemHeight * newIndex;

    _animation = Tween<double>(begin: oldOffset, end: newOffset).animate(
      CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
    );

    // Remover a chave temporariamente
    itemKeys.remove(task);

    _animationController.reset();
    _animationController.forward();
  }

  Widget _buildAnimatedTask() {
    if (!isAnimating || animatedTask == null) return SizedBox.shrink();

    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Positioned(
          top: _animation.value,
          left: 0,
          right: 0,
          child: Transform.rotate(
            angle: isAnimating ? 0.1 : 0.0,
            child: _buildTaskTile(animatedTask!, oldIndex, isInList: false),
          ),
        );
      },
    );
  }

  Widget _buildItem(
      BuildContext context, int index, Animation<double> animation) {
    final task = _tasks[index];
    // Evita mostrar o item sendo animado
    if (isAnimating && (index == oldIndex || index == newIndex)) {
      return SizedBox.shrink();
    }

    return SizeTransition(
      sizeFactor: animation,
      child: _buildTaskTile(task, index),
    );
  }

  Widget _buildRemovedItem(TodoItem task, Animation<double> animation) {
    return SizeTransition(
      sizeFactor: animation,
      child: _buildTaskTile(task, _tasks.indexOf(task)),
    );
  }

  Widget _buildTaskTile(TodoItem task, int index, {bool isInList = true}) {
    // Use GlobalKey apenas para itens na lista
    final key = isInList ? itemKeys.putIfAbsent(task, () => GlobalKey()) : null;

    return Dismissible(
      key: isInList ? ValueKey(task.task) : UniqueKey(),
      confirmDismiss: (direction) async {
        if (direction == DismissDirection.startToEnd) {
          _toggleComplete(index);
          return false;
        } else if (direction == DismissDirection.endToStart) {
          _markForDeletion(index);
          return false;
        }
        return false;
      },
      background: Container(
        color: Colors.green,
        alignment: Alignment.centerLeft,
        padding: EdgeInsets.only(left: 16),
        child: Icon(Icons.check, color: Colors.white),
      ),
      secondaryBackground: Container(
        color: Colors.red,
        alignment: Alignment.centerRight,
        padding: EdgeInsets.only(right: 16),
        child: Icon(Icons.delete, color: Colors.white),
      ),
      child: Container(
        color: index % 2 == 0 ? Colors.white : Colors.grey[200],
        child: ListTile(
          key: key, // Atribui o GlobalKey apenas na ListTile
          contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          textColor: task.isDeleting
              ? Colors.red
              : (index % 2 == 0 ? Colors.black : Colors.black),
          title: Text(
            task.task,
            style: task.completed
                ? TextStyle(
                    decoration: TextDecoration.lineThrough,
                    color: Colors.black)
                : TextStyle(),
          ),
          trailing: task.isDeleting
              ? TextButton(
                  onPressed: _undoDelete,
                  child: Text(
                    "Desfazer",
                    style: TextStyle(color: Colors.red),
                  ),
                )
              : Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Checkbox(
                      value: task.completed,
                      onChanged: (_) => _toggleComplete(index),
                    ),
                    IconButton(
                      icon: Icon(Icons.delete),
                      onPressed: () => _markForDeletion(index),
                    ),
                  ],
                ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Lista de Tarefas"),
      ),
      body: Column(
        children: [
          Padding(
            padding: EdgeInsets.all(8.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    onSubmitted: (value) => _addTask(value),
                    decoration: InputDecoration(
                      border: OutlineInputBorder(),
                      hintText: "Insira uma nova tarefa",
                    ),
                  ),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () => _addTask(_controller.text),
                  child: Text("Incluir"),
                ),
              ],
            ),
          ),
          Expanded(
            child: Stack(
              children: [
                Container(
                  margin: EdgeInsets.all(10),
                  padding: EdgeInsets.all(0),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10),
                    border: Border.all(color: Colors.grey),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey,
                        spreadRadius: 2,
                        blurRadius: 5,
                        offset: Offset(0, 3),
                      ),
                    ],
                    color: Colors.white,
                  ),
                  child: AnimatedList(
                    key: _listKey,
                    padding: EdgeInsets.all(10),
                    initialItemCount: _tasks.length,
                    itemBuilder: (context, index, animation) {
                      return _buildItem(context, index, animation);
                    },
                  ),
                ),
                if (isAnimating) _buildAnimatedTask(),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
              onPressed: _saveTasks,
              child: Text("Salvar Tarefas"),
            ),
          ),
        ],
      ),
    );
  }
}
My whole code for the task list app above is functioning properly, except for the fetch_tasks part. Upon a login, my client isnt properly retrieving and rebuilding the list from the server. Could you fix just this part of the code, so the list is rebuilt upon a proper login?