import { logError } from "@/lib/logger";
import { isValidUUID } from "@/lib/uuid";
import type { RepositoryContext } from "../datastore/repository";
import { BaseRepository } from "../datastore/repository";

export const MemberSessionRepository = (ctx: RepositoryContext) => {
  const repo = new BaseRepository(ctx);

  const FindMemberSession = async (sessionID: string, contactID: string) => {
    const trx = await repo.memberDatastore.startTransaction().execute();
    try {
      if (!isValidUUID(sessionID)) {
        throw new Error("Invalid session ID");
      }

      const sessionRecord = await trx
        .selectFrom("sessions")
        .selectAll()
        .where("pid", "=", sessionID)
        .executeTakeFirstOrThrow();

      const memberRecord = await trx
        .selectFrom("members")
        .innerJoin("users as member_user", "member_user.id", "members.user_id")
        .innerJoin(
          "member_account_types as account_type",
          "account_type.id",
          "members.membership_type_id",
        )
        .innerJoin(
          "member_account_statuses as account_status",
          "account_status.id",
          "members.membership_status_id",
        )
        .select([
          "members.id",
          "members.member_number",
          "members.membership_number",
          "members._is_active as is_active",
          "members._is_deleted as is_deleted",
          "members.created_at",
          "members.updated_at",
          "member_user.id as user_id",
          "member_user.email",
          "member_user._is_active as user_is_active",
          "member_user._is_deleted as user_is_deleted",
          "account_type.id as account_type_id",
          "account_type.name as account_type_name",
          "account_type.ext_account_type_id as account_type_ext_id",
          "account_type.is_active as account_type_is_active",
          "account_status.id as account_status_id",
          "account_status.name as account_status_name",
          "account_status.ext_account_status_id as account_status_ext_id",
          "account_status.is_active as account_status_is_active",
        ])
        .where("member_number", "=", contactID)
        .executeTakeFirstOrThrow();

      const userRecord = await trx
        .selectFrom("users")
        .select([
          "id",
          "email",
          "_is_active",
          "_is_deleted",
          "pid",
          "hashed_password",
          "created_at",
          "updated_at",
        ])
        .where("id", "=", sessionRecord.user_id)
        .executeTakeFirstOrThrow();

      await trx.commit().execute();
      return {
        sessionRecord,
        userRecord,
        externalAccountTypeID: memberRecord.account_type_ext_id,
        memberRecordID: memberRecord.id,
      };
    } catch (err) {
      await trx.rollback().execute();
      logError(err);
      throw new Error("Failed to find member session");
    }
  };

  const FindMemberSessionsByUserId = async (userId: string) => {
    const trx = await repo.memberDatastore.startTransaction().execute();
    try {
      const records = await trx
        .selectFrom("sessions")
        .select([
          "id",
          "application_type",
          "application_version",
          "browser",
          "created_at",
          "device_type",
          "ip_address",
          "location",
          "os",
          "user_id",
          "fcm_token",
        ])
        .where("user_id", "=", userId)
        .orderBy("created_at", "desc")
        .execute();
      await trx.commit().execute();
      return records;
    } catch (err) {
      await trx.rollback().execute();
      logError(err);
      throw new Error("Failed to find member session by user id");
    }
  };

  return { FindMemberSession, FindMemberSessionsByUserId };
};
