import 'dart:convert';
import 'dart:math';
import 'package:dart_casing/dart_casing.dart';
import 'package:flutter/services.dart' as root_bundle;
import 'package:drift/drift.dart';
import 'package:sendtrain/database/database.dart';

Future<void> seedDb(AppDatabase database) async {
  // seed data setup
  final List<List> sessionValues = [
    [
      'Projecting',
      'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
      'Climbers Rock Inc.'
    ],
    [
      'Moonboard',
      'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
      'Beta Bloc'
    ],
    [
      'Off-Wall Training',
      'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
      'Climbers Rock Inc.'
    ],
    [
      'Climbing Outdoors',
      'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
      'Gravity Hamilton'
    ],
    [
      'Volume Session',
      'Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
      'Up the Bloc'
    ],
  ];

  final List<List> mediaItems = [
    [
      'https://www.climbing.com/wp-content/uploads/2022/06/campus-board-e1655470701154.jpeg',
      MediaType.image
    ],
    ['BgheYcxhrsw', MediaType.youtube]
  ];

  final List<String> actionTypes = [
    "[[{\"actionID\": 0, \"name\": \"1, 3, 5\", \"type\": \"repititions\", \"amount\": 1, \"weight\": 0}, {\"actionID\": 1, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 2, \"name\": \"1, 3, 5\", \"type\": \"repititions\", \"amount\": 1, \"weight\": 0}, {\"actionID\": 3, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 4, \"name\": \"1, 3, 5\", \"type\": \"repititions\", \"amount\": 1, \"weight\": 0}, {\"actionID\": 5, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}]]",
    "[[{\"actionID\": 0, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weight\": 80}, {\"actionID\": 1, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 5}, {\"actionID\": 2, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weights\": 80}, {\"actionID\": 3, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 4, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weight\": 80}, {\"actionID\": 5, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 5}, {\"actionID\": 6, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weights\": 80}, {\"actionID\": 7, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 8, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weight\": 80}, {\"actionID\": 9, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 5}, {\"actionID\": 10, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weights\": 80}, {\"actionID\": 11, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 12, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weight\": 80}, {\"actionID\": 13, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 5}, {\"actionID\": 14, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weights\": 80}, {\"actionID\": 15, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}], [{\"actionID\": 16, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weight\": 80}, {\"actionID\": 17, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 5}, {\"actionID\": 18, \"name\": \"Long Pulls\", \"type\": \"seconds\", \"amount\": 5, \"weights\": 80}, {\"actionID\": 19, \"name\": \"Rest\", \"type\": \"seconds\", \"amount\": 300}]]"
  ];

  final int totalSessions = 15;
  final int totalActivities = 6;
  final int totalActions = 5;
  final int totalMedia = 5;
  final random = Random();

  // we gotta build all the activities!
  final jsondata =
      await root_bundle.rootBundle.loadString('assets/exercises.json');
  final exercises = json.decode(jsondata);
  List<int> activityIds = [];

  for (int i = 0; i < exercises.length; i++) {
    var exercise = exercises[i];
    var images = [];
    if (exercise['images'] != null) {
      for (int j = 0; j < exercise['images'].length; j++) {
        var image = exercise['images'][j];
        images.add(
            "https://raw.githubusercontent.com/yuhonas/free-exercise-db/main/exercises/$image");
      }
    }

    Map<Symbol, Value> payload = {
      Symbol('title'): Value<String>(exercise['name']),
      Symbol('description'): Value<String>(json.encode(exercise['instructions'])),
      Symbol('force'): Value<String>(exercise['force'] ?? "")
    };

    // well this fucking sucks
    if (exercise['category'] != null) {
      payload[Symbol('type')] = Value<ActivityType>(ActivityType.values
          .firstWhere((e) =>
              e.toString() ==
              "ActivityType.${Casing.camelCase(exercise['category'])}"));
    }
    if (exercise['level'] != null) {
      payload[Symbol('level')] = Value<ActivityLevel>(ActivityLevel.values
          .firstWhere((e) =>
              e.toString() ==
              "ActivityLevel.${Casing.camelCase(exercise['level'])}"));
    }
    if (exercise['mechanic'] != null) {
      payload[Symbol('mechanic')] = Value<ActivityMechanic>(
          ActivityMechanic.values.firstWhere((e) =>
              e.toString() ==
              "ActivityMechanic.${Casing.camelCase(exercise['mechanic'])}"));
    }
    if (exercise['equipment'] != null) {
      payload[Symbol('equipment')] = Value<ActivityEquipment>(
          ActivityEquipment.values.firstWhere((e) =>
              e.toString() ==
              "ActivityEquipment.${Casing.camelCase(exercise['equipment'])}"));
    }
    if (exercise['primaryMuscles'].isNotEmpty) {
      payload[Symbol('primaryMuscles')] = Value<ActivityMuscle>(
          ActivityMuscle.values.firstWhere((e) =>
              e.toString() ==
              "ActivityMuscle.${Casing.camelCase(exercise['primaryMuscles'].first)}"));
    }
    if (exercise['secondaryMuscles'].isNotEmpty) {
      payload[Symbol('secondaryMuscles')] = Value<ActivityMuscle>(
          ActivityMuscle.values.firstWhere((e) =>
              e.toString() ==
              "ActivityMuscle.${Casing.camelCase(exercise['secondaryMuscles'].first)}"));
    }

    activityIds.add(await database
        .into(database.activities)
        .insert(Function.apply(ActivitiesCompanion.new, [], payload))
        .then((activityId) async {
      for (int m = 0; m < images.length; m++) {
        final mediaItem = images[m];
        await database
            .into(database.mediaItems)
            .insert(MediaItemsCompanion.insert(
                title: exercise['name'],
                description:
                   exercise['name'],
                reference: mediaItem,
                type: MediaType.image))
            .then((mediaId) async {
          await database.into(database.objectMediaItems).insert(
              ObjectMediaItemsCompanion.insert(
                  objectId: activityId,
                  mediaId: mediaId,
                  objectType: ObjectType.activities));
        });
      }
      return activityId;
    }));
  }

  // seed loop
  for (int i = 0; i < totalSessions; i++) {
    // session things
    var status = SessionStatus.completed;
    if (i == 0) status = SessionStatus.started;
    if (i == 1) status = SessionStatus.pending;

    final sessionValue = sessionValues[random.nextInt(sessionValues.length)];
    await database
        .into(database.sessions)
        .insert(SessionsCompanion.insert(
            title: sessionValue[0],
            content: sessionValue[1],
            status: status,
            address: Value(sessionValue[2]),
            achievements: Value(
                "[\"achievement 1\", \"achievement 2\", \"achievement 3\"]"),
            date: Value(DateTime.now())))
        .then((sessionId) async {
      // activities things
      for (int j = 0; j <= random.nextInt(totalActivities); j++) {
        int activityId = random.nextInt(activityIds.length);
        activityIds.removeAt(activityId);

        await database
            .into(database.sessionActivities)
            .insert(SessionActivitiesCompanion.insert(
              sessionId: sessionId,
              activityId: activityId,
              position: j,
              results: Value("results json, will need to test"),
            ));

        // actions
        for (int k = 0; k <= random.nextInt(totalActions); k++) {
          await database
              .into(database.actions)
              .insert(ActionsCompanion.insert(
                  title: 'Test action $k',
                  description:
                      '$k Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
                  set: actionTypes[random.nextInt(actionTypes.length)]))
              .then((actionId) async {
            // add activity action association
            await database.into(database.activityActions).insert(
                ActivityActionsCompanion.insert(
                    activityId: activityId, actionId: actionId, position: k));
          });
        }
      }

      for (int n = 0; n <= random.nextInt(totalMedia); n++) {
        final mediaItem = mediaItems[random.nextInt(mediaItems.length)];
        await database
            .into(database.mediaItems)
            .insert(MediaItemsCompanion.insert(
                title: 'Media title $n',
                description:
                    'Media description $n Beta pully beta beta pinch one arm crimpy. Futuristic pinch, dyno dynamic drop knee climb. Climbing ondra slopey onsight beta ondra power endurance.',
                reference: mediaItem[0],
                type: mediaItem[1]))
            .then((mediaId) async {
          await database.into(database.objectMediaItems).insert(
              ObjectMediaItemsCompanion.insert(
                  objectId: sessionId,
                  mediaId: mediaId,
                  objectType: ObjectType.sessions));
        });
      }

      await database
          .into(database.mediaItems)
          .insert(MediaItemsCompanion.insert(
              title: 'Locations details',
              description:
                  '5155 Harvester Rd #1, Burlington, ON L7L 6V2, Canada',
              reference:
                  'https://lh3.googleusercontent.com/places/ANXAkqHwtb5oRMGG3haJkaHeTxdTI1lQ17RgvkCXwzA1dGV53BXPbHrdXIs1mLC_-4exyRW8dbYhMOeiOCHJqGeVBx-dNtABZAl9tQA=s4800-w800',
              type: MediaType.location))
          .then((mediaId) async {
        await database.into(database.objectMediaItems).insert(
            ObjectMediaItemsCompanion.insert(
                objectId: sessionId,
                mediaId: mediaId,
                objectType: ObjectType.sessions));
      });
    });
  }
}