import { int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core';
import { user } from './user.ts';
import type { MySql2Database } from 'drizzle-orm/mysql2';
import { desc, eq, inArray, isNotNull } from 'drizzle-orm';
import { generateRandomString } from '@util/random.ts';

type Database = MySql2Database<{ feedback: typeof feedback }>;

export const feedback = mysqlTable('feedback', {
  id: int('id').primaryKey().autoincrement(),
  event: varchar('event', { length: 255 }).notNull(),
  title: varchar('title', { length: 255 }),
  content: text('content'),
  urlHash: varchar('url_hash', { length: 255 }).unique().notNull(),
  lastChanged: timestamp('last_changed', { mode: 'date' }).notNull().defaultNow().onUpdateNow(),
  userId: int('user_id').references(() => user.id)
});

export type AddFeedbackReq = {
  event: string;
  content: string;
};

export type AddUserFeedbacksReq = {
  event: string;
  title: string;
  uuids: string[];
};

export type SubmitFeedbackReq = {
  urlHash: string;
  content: string;
};

export type GetFeedbacksReq = {
  includeBlanks?: boolean | null;
};

export type GetFeedbackByUrlHash = {
  urlHash: string;
};

export async function addFeedback(db: Database, values: AddFeedbackReq) {
  return db.insert(feedback).values({
    event: values.event,
    content: values.content,
    urlHash: generateRandomString(16)
  });
}

export async function addUserFeedbacks(db: Database, values: AddUserFeedbacksReq) {
  const users = await db.select({ id: user.id, uuid: user.uuid }).from(user).where(inArray(user.uuid, values.uuids));

  const userFeedbacks = users.map((user) => ({
    id: user.id,
    uuid: user.uuid!,
    urlHash: generateRandomString(16)
  }));

  await db.insert(feedback).values(
    userFeedbacks.map((feedback) => ({
      event: values.event,
      title: values.title,
      urlHash: feedback.urlHash,
      userId: feedback.id
    }))
  );

  return userFeedbacks;
}

export async function submitFeedback(db: Database, values: SubmitFeedbackReq) {
  return db
    .update(feedback)
    .set({
      content: values.content
    })
    .where(eq(feedback.urlHash, values.urlHash));
}

export async function getFeedbacks(db: Database, values: GetFeedbacksReq) {
  return db
    .select({
      id: feedback.id,
      event: feedback.event,
      title: feedback.title,
      content: feedback.content,
      urlHash: feedback.urlHash,
      lastChanged: feedback.lastChanged,
      username: user.username
    })
    .from(feedback)
    .leftJoin(user, eq(feedback.userId, user.id))
    .where(!values.includeBlanks ? isNotNull(feedback.content) : undefined)
    .orderBy(desc(feedback.id));
}

export async function getFeedbackByUrlHash(db: Database, values: GetFeedbackByUrlHash) {
  return db.query.feedback.findFirst({
    where: eq(feedback.urlHash, values.urlHash)
  });
}
