import 'package:drift/drift.dart';
import 'package:drift_flutter/drift_flutter.dart';
import 'package:sendtrain/daos/actions_dao.dart';
import 'package:sendtrain/daos/activities_dao.dart';
import 'package:sendtrain/daos/activity_actions_dao.dart';
import 'package:sendtrain/daos/media_items_dao.dart';
import 'package:sendtrain/daos/object_media_items_dao.dart';
import 'package:sendtrain/daos/session_activities_dao.dart';
import 'package:sendtrain/daos/sessions_dao.dart';
import 'package:sendtrain/database/seed.dart';

part 'database.g.dart';

@DriftDatabase(tables: [
  Sessions,
  SessionActivities,
  Activities,
  ActivityActions,
  Actions,
  ObjectMediaItems,
  MediaItems
], daos: [
  SessionsDao,
  ActivitiesDao,
  MediaItemsDao,
  ObjectMediaItemsDao,
  SessionActivitiesDao,
  ActivityActionsDao,
  ActionsDao
])
class AppDatabase extends _$AppDatabase {
  // After generating code, this class needs to define a `schemaVersion` getter
  // and a constructor telling drift where the database should be stored.
  // These are described in the getting started guide: https://drift.simonbinder.eu/setup/
  AppDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 35;

  @override
  MigrationStrategy get migration {
    return MigrationStrategy(
      onCreate: (m) async {
        await m.createAll().then((r) async {
          await seedDb(this);
        }); // create all tables
      },
      beforeOpen: (details) async {
        /// Enable foreign_keys
        await customStatement('PRAGMA foreign_keys = ON');
      },
    );
  }

  static QueryExecutor _openConnection() {
    // `driftDatabase` from `package:drift_flutter` stores the database in
    // `getApplicationDocumentsDirectory()`.
    return driftDatabase(name: 'sendtrain');
  }
}

enum SessionStatus { pending, started, completed, missed }

class Sessions extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 3, max: 32)();
  TextColumn get content => text().named('body')();
  TextColumn get status => textEnum<SessionStatus>()();
  TextColumn get achievements => text().nullable()();
  TextColumn get address => text().withLength(min: 3, max: 256).nullable()();
  DateTimeColumn get date => dateTime().nullable()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

class SessionActivities extends Table {
  IntColumn get id => integer().autoIncrement()();
  IntColumn get sessionId =>
      integer().references(Sessions, #id, onDelete: KeyAction.cascade)();
  IntColumn get activityId =>
      integer().references(Activities, #id, onDelete: KeyAction.cascade)();
  IntColumn get position => integer()();
  TextColumn get results => text().nullable()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

enum ActivityCategories { fundamentals, conditioning, advanced, custom, pro }

enum ActivityType {
  strength,
  stretching,
  plyometrics,
  strongman,
  powerlifting,
  cardio,
  olympicWeightlifting
}

enum ActivityLevel { beginner, intermediate, expert }

enum ActivityMechanic { compound, isolation }

enum ActivityEquipment {
  bodyOnly,
  machine,
  other,
  foamRoll,
  kettlebells,
  dumbbell,
  cable,
  barbell,
  bands,
  medicineBall,
  exerciseBall,
  eZCurlBar
}

enum ActivityMuscle {
  abdominals,
  hamstrings,
  calves,
  shoulders,
  adductors,
  glutes,
  quadriceps,
  biceps,
  forearms,
  abductors,
  triceps,
  chest,
  lowerBack,
  traps,
  middleBack,
  lats,
  neck
}

class Activities extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 3, max: 100)();
  TextColumn get type => textEnum<ActivityType>().nullable()();
  TextColumn get description => text().named('body').nullable()();
  TextColumn get category => textEnum<ActivityCategories>().nullable()();
  // from exercises.json
  TextColumn get force => text().nullable()();
  TextColumn get level => textEnum<ActivityLevel>().nullable()();
  TextColumn get mechanic => textEnum<ActivityMechanic>().nullable()();
  TextColumn get equipment => textEnum<ActivityEquipment>().nullable()();
  TextColumn get primaryMuscles => textEnum<ActivityMuscle>().nullable()();
  TextColumn get secondaryMuscles => textEnum<ActivityMuscle>().nullable()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

class ActivityActions extends Table {
  IntColumn get id => integer().autoIncrement()();
  IntColumn get activityId => integer().references(Activities, #id, onDelete: KeyAction.cascade)();
  IntColumn get actionId =>
      integer().references(Actions, #id, onDelete: KeyAction.cascade)();
  IntColumn get sessionId => integer().references(Sessions, #id, onDelete: KeyAction.cascade)();
  IntColumn get position => integer()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

enum RepType { time, count }

enum ActionStatus { pending, started, paused, complete }

class Actions extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 3, max: 64)();
  TextColumn get description => text().named('body')();
  IntColumn get totalSets => integer()();
  TextColumn get totalReps => text().withLength(min: 1, max: 32)();
  IntColumn get restBeforeSets => integer().nullable()();
  IntColumn get restBetweenSets => integer().nullable()();
  IntColumn get restBetweenReps => integer().nullable()();
  IntColumn get restAfterSets => integer().nullable()();
  TextColumn get repType => textEnum<RepType>()();
  IntColumn get repLength => integer().nullable()();
  TextColumn get repWeights => text().nullable()();
  TextColumn get setWeights => text().nullable()();
  BoolColumn get isAlternating => boolean().withDefault(Variable(false))();
  TextColumn get tempo => text().withLength(min: 6, max: 36).nullable()();
  TextColumn get status =>
      textEnum<ActionStatus>().withDefault(Variable('pending'))();
  TextColumn get state => text().withDefault(Variable(
      "{\"currentSet\": 0, \"currentRep\": 0, \"currentActionType\": 0, \"currentTime\": 0, \"currentAction\": 0}"))();
  TextColumn get set => text()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

enum ObjectType {
  actions,
  activities,
  sessions,
}

class ObjectMediaItems extends Table {
  IntColumn get id => integer().autoIncrement()();
  IntColumn get objectId => integer()();
  TextColumn get objectType => textEnum<ObjectType>()();
  IntColumn get mediaId =>
      integer().references(MediaItems, #id, onDelete: KeyAction.cascade)();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}

enum MediaType { youtube, image, location, localImage, localVideo }

class MediaItems extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get title => text().withLength(min: 3, max: 64)();
  TextColumn get description => text().named('body')();
  TextColumn get reference => text()();
  TextColumn get type => textEnum<MediaType>()();
  DateTimeColumn get createdAt =>
      dateTime().withDefault(Variable(DateTime.now()))();
}