content: import 'package:dart_mappable/dart_mappable.dart';
  import 'package:http/http.dart' as http;
  import 'package:jaspr/jaspr.dart';
  import 'package:jaspr_riverpod/jaspr_riverpod.dart';
  import 'package:jaspr_riverpod/legacy.dart';
  
  import '../adapters/html.dart';
  import '../components/elements/snackbar.dart';
  import '../models/gist.dart';
  import '../models/project.dart';
  import '../models/tutorial.dart';
  import 'dart_service_provider.dart';
  
  final fetchedGistProvider = FutureProvider.family((ref, String id) async {
    try {
      var response = await http.get(Uri.parse('https://api.github.com/gists/$id'));
      if (response.statusCode == 404) throw 'Gist does not exist';
      if (response.statusCode != 200) throw 'Unknown error ${response.statusCode}';
  
      var gist = GistDataMapper.fromJson(response.body);
      return ProjectData.fromGist(gist);
    } catch (e) {
      ref.read(snackBarProvider.notifier).state = 'Error loading gist $id: $e.';
      return null;
    }
  });
  
  final fetchedSampleProvider = FutureProvider.family((ref, String id) async {
    try {
      var project = await ref.read(dartServiceProvider).getSample(id);
      if (project.project != null) {
        return project.project!;
      } else {
        throw project.error!;
      }
    } catch (e) {
      ref.read(snackBarProvider.notifier).state = 'Error loading sample $id: $e.';
      return null;
    }
  });
  
  final fetchedTutorialProvider = FutureProvider.family((ref, String id) async {
    try {
      var project = await ref.read(dartServiceProvider).getTutorial(id);
      if (project.tutorial != null) {
        return TutorialData.fromConfig(project.tutorial!);
      } else {
        throw project.error!;
      }
    } catch (e) {
      ref.read(snackBarProvider.notifier).state = 'Error loading tutorial $id: $e.';
      return null;
    }
  });
  
  final storageProvider = Provider((ref) => window.localStorage);
  
  final storedProjectProvider = Provider.autoDispose((ref) {
    if (!window.localStorage.containsKey('project')) {
      return null;
    }
    try {
      return ProjectDataBaseMapper.fromJson(window.localStorage['project']!);
    } on MapperException catch (_) {
      window.localStorage.remove('project');
      return null;
    }
  });
  
  final selectedSampleProvider = StateProvider<ProjectData?>((ref) => null);
  
  final loadedProjectProvider = Provider<AsyncValue<ProjectDataBase>>((ref) {
    if (!kIsWeb) {
      return AsyncValue.loading(); // Don't load on server
    }
  
    var storedProject = ref.read(storedProjectProvider);
    var uri = Uri.parse(ref.binding.currentUrl);
    var queryId = uri.queryParameters['gist'] != null
        ? 'gist-${uri.queryParameters['gist']}'
        : uri.queryParameters['sample'] != null
        ? 'sample-${uri.queryParameters['sample']}'
        : uri.queryParameters['tutorial'] != null
        ? 'tutorial-${uri.queryParameters['tutorial']}'
        : null;
    if (storedProject != null && storedProject.id == queryId) {
      return AsyncValue.data(storedProject);
    } else {
      var gistId = uri.queryParameters['gist'];
      var sampleId = uri.queryParameters['sample'];
      var tutorialId = uri.queryParameters['tutorial'];
  
      AsyncValue<ProjectDataBase?> project;
  
      if (gistId != null) {
        project = ref.watch(fetchedGistProvider(gistId));
      } else if (sampleId != null) {
        project = ref.watch(fetchedSampleProvider(sampleId));
      } else if (tutorialId != null) {
        project = ref.watch(fetchedTutorialProvider(tutorialId));
      } else {
        project = AsyncValue.data(createDefaultProject());
      }
  
      return project.whenData((project) => project?.copy() ?? createDefaultProject());
    }
  });
  
  final projectNameProvider = Provider<String?>((ref) => ref.watch(loadedProjectProvider).value?.description);
  
  final isTutorialProvider = Provider((ref) => ref.watch(loadedProjectProvider.select((l) => l.value is TutorialData)));
  
  ProjectDataBase createDefaultProject() {
    return ProjectData(
      id: 'basic',
      description: 'jaspr_basic',
      cssFile:
          'html, body {\n'
          '  display: flex;\n'
          '  justify-content: center;\n'
          '  align-items: center;\n'
          '  height: 100%;\n'
          '  color: white;\n'
          '  font-family: sans-serif;\n'
          '}',
      mainDartFile:
          "import 'package:jaspr/jaspr.dart';\n\n"
          "void main() {\n"
          "  runApp(h1([\n"
          "    text('Hello World!'),\n"
          "  ]));\n"
          "}",
    );
  }
  