comment faire pour créer l'annonce a distance comme le local c'est fait : import 'package:flutter/material.dart';
import 'package:sae_mobile/models/annonce.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:sae_mobile/models/queries/distant/annonce.dart' as daq;
import 'package:sae_mobile/models/User.dart' as user_model;
import 'package:sae_mobile/models/Builder.dart' as builder_model;
import 'package:sae_mobile/models/queries/distant/typeAnnonce.dart';
import 'package:sae_mobile/models/queries/local/annonce.dart' as aq;
import 'package:sae_mobile/models/TypeAnnonce.dart';

final SupabaseClient supabaseClient = Supabase.instance.client;

class CreateAnnonce extends StatefulWidget {
  const CreateAnnonce({Key? key}) : super(key: key);

  @override
  State<CreateAnnonce> createState() => _CreateAnnonceState();
}

class _CreateAnnonceState extends State<CreateAnnonce> {
  final TextEditingController _titleController = TextEditingController();
  final TextEditingController _descriptionController = TextEditingController();
  final TextEditingController _dateDebController = TextEditingController();
  final TextEditingController _dateFinController = TextEditingController();
  int? _selectedTypeAnnonceIndex;
  List<TypeAnnonce>? typesAnnonce;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Create Annonce'),
        TextField(
          controller: _titleController,
          decoration: const InputDecoration(labelText: 'Title'),
        ),
        TextField(
          controller: _descriptionController,
          decoration: const InputDecoration(labelText: 'Description'),
        ),
        TextField(
            controller: _dateDebController,
            decoration: const InputDecoration(
                icon: Icon(Icons.calendar_today), labelText: "Enter Date"),
            readOnly: true,
            onTap: () async {
              DateTime? date = await showDatePicker(
                context: context,
                initialDate: DateTime.now(),
                firstDate: DateTime(2000),
                lastDate: DateTime(2100),
              );
              if (date != null) {
                _dateDebController.text = date.toString();
              }
            }),
        TextField(
            controller: _dateFinController,
            decoration: const InputDecoration(
                icon: Icon(Icons.calendar_today), labelText: "Enter Date"),
            readOnly: true,
            onTap: () async {
              DateTime? date = await showDatePicker(
                context: context,
                initialDate: DateTime.now(),
                firstDate: DateTime(2000),
                lastDate: DateTime(2100),
              );
              if (date != null) {
                _dateFinController.text = date.toString();
              }
            }),
        FutureBuilder<List<TypeAnnonce>>(
          future: builder_model.Builder.buildTypesAnnonceDistant(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const CircularProgressIndicator();
            }
            if (snapshot.hasError) {
              return Text('Error: ${snapshot.error}');
            }
            typesAnnonce = snapshot.data!;
            if (_selectedTypeAnnonceIndex == null && typesAnnonce!.isNotEmpty) {
              _selectedTypeAnnonceIndex = 0;
            }
            return DropdownButton<int>(
              value: _selectedTypeAnnonceIndex,
              items: typesAnnonce!.asMap().entries.map((entry) {
                return DropdownMenuItem<int>(
                  value: entry.key,
                  child: Text(entry.value.libelle),
                );
              }).toList(),
              onChanged: (int? newIndex) {
                setState(() {
                  _selectedTypeAnnonceIndex = newIndex;
                });
              },
              hint: Text('Select a category'),
            );
          },
        ),
        FutureBuilder(
          future: builder_model.Builder.buildUserById(
              supabaseClient.auth.currentUser!.id),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const CircularProgressIndicator();
            }
            if (snapshot.hasError) {
              return Text('Error: ${snapshot.error}');
            }
            final user = snapshot.data as user_model.User;

            return ElevatedButton(
              onPressed: () async {
                final selectedTypeAnnonce =
                    typesAnnonce![_selectedTypeAnnonceIndex!];
                await aq.AnnonceQueries.createAnnonce(
                  user.id,
                  _titleController.text,
                  _descriptionController.text,
                  DateTime.parse(_dateDebController.text),
                  DateTime.parse(_dateFinController.text),
                  1,
                  1,
                  selectedTypeAnnonce!.id,
                );
                await daq.AnnonceQueries.publishAnnonce(annonce);

                Navigator.pushNamed(context, '/categorie');
              },
              child: Text("Créer l'annonce"),
            );
          },
        ),
      ],
    );
  }
}
import 'package:sae_mobile/database/DatabaseHelper.dart';

class AnnonceQueries {
  static Future<void> createAnnonce(
      String id_u,
      String titre,
      String description,
      DateTime dateDeb,
      DateTime dateFin,
      int idEtat,
      int idObj,
      int idType) async {
    final db = await DatabaseHelper().db;
    String id_a = DateTime.now().millisecondsSinceEpoch.toString();
    await db.insert('ANNONCES', {
      'id': id_a,
      'titre': titre,
      'description': description,
      'dateDeb': dateDeb.toIso8601String(),
      'dateFin': dateFin.toIso8601String(),
      'idEtat': idEtat,
      'idObj': idObj,
      'idType': idType,
    });
    await db.insert('PUBLIE', {
      'id_a': id_a,
      'id_u': id_u,
    });
  }

  static Future<List<Map<String, dynamic>>> getAnnonces() async {
    final db = await DatabaseHelper().db;
    final List<Map<String, dynamic>> annonces = await db.query('ANNONCES');
    return annonces;
  }
  

  static Future<Map<String, dynamic>> getAnnonceById(String id) async {
    final db = await DatabaseHelper().db;
    final List<Map<String, dynamic>> annonces =
        await db.query('ANNONCES', where: 'id = ?', whereArgs: [id]);
    return annonces.first;
  }

  static Future<void> updateAnnonceEtat(String id, int etat) async {
    final db = await DatabaseHelper().db;
    await db.update('ANNONCES', {'idEtat': etat},
        where: 'id = ?', whereArgs: [id]);
  }

  static Future<void> updateAnnonceId(String id, String newId) async {
    final db = await DatabaseHelper().db;
    await db.update('ANNONCES', {'id': newId},
        where: 'id = ?', whereArgs: [id]);
  }

  static Future<void> deleteAnnonce(String id) async {
    final db = await DatabaseHelper().db;
    await db.delete('ANNONCES', where: 'id = ?', whereArgs: [id]);
  }

  static Future<List<Map<String, dynamic>>> getAnnoncesByUser(String id) async {
    final db = await DatabaseHelper().db;
    final List<Map<String, dynamic>> annonces = await db.rawQuery('''
    SELECT ANNONCES.* 
    FROM ANNONCES 
    JOIN PUBLIE ON ANNONCES.id = PUBLIE.id_a 
    WHERE PUBLIE.id_u = ?
  ''', [id]);
    print("Les annonces local" + annonces.toString());
    return annonces;
  }
}
import 'package:sae_mobile/models/annonce.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

final SupabaseClient supabaseClient = Supabase.instance.client;

class AnnonceQueries {
  static Future<String> publishAnnonce(Annonce annonce) async {
    print("publishAnnonce");
    print(annonce.dateDeb.toIso8601String());
    print(annonce.dateFin.toIso8601String());
    print(annonce.titre);
    PostgrestList result = await supabaseClient.from('ANNONCES').insert({
      'titre': annonce.titre,
      'description': annonce.description,
      'dateDeb': annonce.dateDeb.toIso8601String(),
      'dateFin': annonce.dateFin.toIso8601String(),
      'idType': 1,
      'idEtat': 2,
    }).select('id');
    print("result");

    if (result.isEmpty) {
      throw Exception('Failed to create annonce');
    }

    String id = result[0]['id'];

    await supabaseClient.from('PUBLIE').insert({
      'id_a': id,
      'id_user': annonce.auteur.id,
    });

    return id;
  }

  static Future<PostgrestList> getAnnonces() async {
    final response = await supabaseClient.from('ANNONCES').select();
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnoncesByType(String id) async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('idType', id);
    if (response.isEmpty) {
      throw Exception('Aucune annonce de ce type');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceNonRepondu() async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('idEtat', 2);
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceRepondu(String id_u) async {
    final ids_a =
        await supabaseClient.from('REPONDS').select().eq('id_user', id_u);
    if (ids_a.isEmpty) {
      throw Exception("Pas d'annonces repondues");
    }
    final response = await supabaseClient
        .from('ANNONCES')
        .select()
        .inFilter('id', ids_a.map((e) => e['id_a']).toList());
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceCloturer(String id_u) async {
    final ids_a =
        await supabaseClient.from('REPONDS').select().eq('id_user', id_u);
    if (ids_a.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    final response = await supabaseClient.from('ANNONCES').select().inFilter(
        'id',
        ids_a.map((e) => e['id_a']).where((e) => e['id_etat'] == 3).toList());
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceById(String id) async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('id', id);
    if (response.isEmpty) {
      throw Exception('Failed to get annonce');
    }
    return response;
  }

  static Future<String> getAuteurAnnonce(String id) async {
    final response =
        await supabaseClient.from('PUBLIE').select().eq('id_a', id);
    if (response.isEmpty) {
      throw Exception('Failed to get auteur');
    }
    return response[0]['id_user'];
  }

  static Future<void> accepterAnnonce(String id_a, String id_user) async {
    await supabaseClient.from('REPONDS').insert({
      'id_a': id_a,
      'id_user': id_user,
    });
  }

  static Future<void> updateAnnonceEtat(String id, int etat) async {
    await supabaseClient.from('ANNONCES').update({'idEtat': etat}).eq('id', id);
  }

  static Future<void> mettreAvis(String id_a, String id_u, String avis) async {
    await supabaseClient.from('AVIS').insert({
      'id_a': id_a,
      'id_user': id_u,
      'avis': avis,
    });
  }

  static Future<PostgrestList> getAnnonceAvis(String id_a) async {
    final response = await supabaseClient
        .from('AVIS')
        .select('avis, users:id_user (username)')
        .eq('id_a', id_a);
    if (response.isEmpty) {
      throw Exception('Failed to get avis');
    }
    return response;
  }
}
  /// Construit une annonce à partir de son id.
  ///
  /// [id] est l'id de l'annonce.
  ///
  /// Retourne un objet de type [Annonce].
  static Future<Annonce> buildAnnonceById(String id) async {
    final data = await aql.AnnonceQueries.getAnnonceById(id);

    String user_id = await aqd.AnnonceQueries.getAuteurAnnonce(data['id']);
    return Annonce.fromJson(data, await buildUserById(user_id));
  }