import { prisma } from '@/db';
import { User } from '@/generated/prisma/client';
import { SessionModel } from '@/generated/prisma/models';
import { DB_TABLE, LOG_ACTION } from '@/types/enum';
import {
  acOrg,
  adminOrg,
  member,
  owner,
} from '@lib/auth/organization-permissions';
import { ac, admin, user } from '@lib/auth/permissions';
import { createAuditLog, getInitialOrganization } from '@service/repository';
import { betterAuth } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { admin as adminPlugin, organization } from 'better-auth/plugins';

export interface Session {
  session: SessionModel | null | undefined;
  user?: User;
}

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: 'postgresql',
  }),
  experimental: { joins: true },
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: false,
  },
  trustedOrigins: ['http://localhost:3001'],
  advanced: {
    database: {
      generateId: false,
    },
  },
  plugins: [
    adminPlugin({
      ac,
      roles: { admin, user },
      defaultRole: 'user',
    }),
    organization({
      ac: acOrg,
      roles: { owner, admin: adminOrg, member },
      schema: {
        organization: {
          modelName: 'house',
          additionalFields: {
            color: {
              type: 'string',
              defaultValue: '#000000',
            },
          },
        },
      },
    }),
  ],
  databaseHooks: {
    user: {
      create: {
        after: async (user) => {
          await auth.api.createOrganization({
            body: {
              name: `${user.name || 'User'}'s House`,
              slug: `${user.name?.toLowerCase().replace(/\s+/g, '-')}-house-${Date.now()}`,
              userId: user.id,
              color: '#000000',
            },
          });
          await prisma.setting.create({
            data: {
              key: user.id,
              value: '{"language": "en"}',
              description: '',
              relation: 'user',
            },
          });
        },
      },
    },
    session: {
      create: {
        before: async (session) => {
          const organization = await getInitialOrganization(session.userId);
          return {
            data: {
              ...session,
              activeOrganizationId: organization?.id,
            },
          };
        },
        after: async (session, context) => {
          if (context?.path.includes('/sign-in')) {
            await createAuditLog({
              action: LOG_ACTION.SIGN_IN,
              tableName: DB_TABLE.SESSION,
              recordId: session.id,
              oldValue: '',
              newValue: JSON.stringify(session),
              userId: session.userId,
            });
          }
        },
      },
      delete: {
        after: async (session, context) => {
          if (context?.path === '/sign-out') {
            await createAuditLog({
              action: LOG_ACTION.SIGN_OUT,
              tableName: DB_TABLE.SESSION,
              recordId: session.id,
              oldValue: JSON.stringify(session),
              newValue: '',
              userId: session.userId,
            });
          }
        },
      },
    },
  },
});
