import type { Kysely } from "kysely";
import { sql } from "kysely";
import type { DB } from "../datastore/db";

export const AdminActivityLogRepository = (db: Kysely<DB>) => ({
  async insertLog(log: {
    admin_email: string;
    action: string;
    method: string;
    url: string;
    status_code: number;
    payload?: string | null;
    before_payload?: string | null;
    ip_address?: string | null;
    user_agent?: string | null;
    log_category?: string;
    metadata?: any;
    performed_at: Date;
  }) {
    return await db
      .insertInto("admin_activity_log" as any)
      .values(log as any)
      .execute();
  },

  async searchLogs(params: {
    admin_email?: string[];
    log_category?: string[];
    method?: string[];
    status_group?: string[];
    from_date?: string;
    to_date?: string;
    entity_id?: string;
    search?: string;
    limit?: number;
    offset?: number;
  }) {
    let query = db
      .selectFrom("admin_activity_log" as any)
      .selectAll()
      .orderBy("performed_at", "desc");

    if (params.admin_email?.length) {
      query = query.where("admin_email", "in", params.admin_email);
    }

    if (params.log_category?.length) {
      query = query.where("log_category", "in", params.log_category);
    }

    if (params.method?.length) {
      query = query.where("method", "in", params.method);
    }

    if (params.status_group?.length) {
      query = query.where((eb) => {
        const conditions: any[] = [];
        if (params.status_group?.includes("2xx Success")) {
          conditions.push(
            eb("status_code", ">=", 200).and("status_code", "<", 300),
          );
        }
        if (params.status_group?.includes("4xx Client Error")) {
          conditions.push(
            eb("status_code", ">=", 400).and("status_code", "<", 500),
          );
        }
        if (params.status_group?.includes("5xx Server Error")) {
          conditions.push(
            eb("status_code", ">=", 500).and("status_code", "<", 600),
          );
        }
        return eb.or(conditions);
      });
    }

    if (params.from_date) {
      query = query.where("performed_at", ">=", new Date(params.from_date));
    }

    if (params.to_date) {
      query = query.where("performed_at", "<=", new Date(params.to_date));
    }

    if (params.entity_id) {
      query = query.where(sql`metadata->>'entityId'`, "=", params.entity_id);
    }

    if (params.search) {
      const search = `%${params.search}%`;
      query = query.where((eb) =>
        eb.or([
          eb("admin_email", "ilike", search),
          eb("action", "ilike", search),
          eb("url", "ilike", search),
        ]),
      );
    }

    const { limit = 50, offset = 0 } = params;

    const items = await query.limit(limit).offset(offset).execute();

    // Also get total count
    const totalCountQuery = db
      .selectFrom("admin_activity_log" as any)
      .select((eb) => eb.fn.count("id").as("count"));

    // Apply same filters
    let filteredCountQuery = totalCountQuery;
    if (params.admin_email?.length) {
      filteredCountQuery = filteredCountQuery.where(
        "admin_email",
        "in",
        params.admin_email,
      );
    }
    if (params.log_category?.length) {
      filteredCountQuery = filteredCountQuery.where(
        "log_category",
        "in",
        params.log_category,
      );
    }
    if (params.method?.length) {
      filteredCountQuery = filteredCountQuery.where(
        "method",
        "in",
        params.method,
      );
    }
    if (params.status_group?.length) {
      filteredCountQuery = filteredCountQuery.where((eb) => {
        const conditions: any[] = [];
        if (params.status_group?.includes("2xx Success")) {
          conditions.push(
            eb("status_code", ">=", 200).and("status_code", "<", 300),
          );
        }
        if (params.status_group?.includes("4xx Client Error")) {
          conditions.push(
            eb("status_code", ">=", 400).and("status_code", "<", 500),
          );
        }
        if (params.status_group?.includes("5xx Server Error")) {
          conditions.push(
            eb("status_code", ">=", 500).and("status_code", "<", 600),
          );
        }
        return eb.or(conditions);
      });
    }
    if (params.from_date) {
      filteredCountQuery = filteredCountQuery.where(
        "performed_at",
        ">=",
        new Date(params.from_date),
      );
    }
    if (params.to_date) {
      filteredCountQuery = filteredCountQuery.where(
        "performed_at",
        "<=",
        new Date(params.to_date),
      );
    }
    if (params.entity_id) {
      filteredCountQuery = filteredCountQuery.where(
        sql`metadata->>'entityId'`,
        "=",
        params.entity_id,
      );
    }
    if (params.search) {
      const search = `%${params.search}%`;
      filteredCountQuery = filteredCountQuery.where((eb) =>
        eb.or([
          eb("admin_email", "ilike", search),
          eb("action", "ilike", search),
          eb("url", "ilike", search),
        ]),
      );
    }

    const countResult = await filteredCountQuery.executeTakeFirst();
    const totalCount = Number(countResult?.count || 0);

    return { items, totalCount };
  },

  async deleteAllLogs(ids?: string[]) {
    let query = db.deleteFrom("admin_activity_log" as any);
    if (ids && ids.length > 0) {
      query = query.where("id", "in", ids as any);
    }
    return await query.execute();
  },
});
