import { initTRPC, TRPCError } from '@trpc/server';
import { z } from 'zod';
import { eq, and } from 'drizzle-orm';
import { projects, projectMembers } from '../../src/db/schema';
import type { TRPCContext } from './types';

// Initialize tRPC with context
const t = initTRPC.context<TRPCContext>().create();

// Middleware for authentication
const isAuthenticated = t.middleware(({ ctx, next }) => {
  if (!ctx.clerkUserId) {
    throw new TRPCError({ code: 'UNAUTHORIZED', message: 'User not authenticated' });
  }
  return next({ ctx: { ...ctx, clerkUserId: ctx.clerkUserId } });
});

// Middleware for database access and user lookup
const hasDb = t.middleware(async ({ ctx, next }) => {
  if (!ctx.db) {
    throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Database not available' });
  }
  
  let userId: number | undefined;
  if (ctx.clerkUserId) {
    const { users } = await import('../../src/db/schema');
    const userRows = await ctx.db.select({ id: users.id })
      .from(users)
      .where(eq(users.clerkId, ctx.clerkUserId));
    if (userRows.length > 0) {
      userId = userRows[0].id;
    }
  }
  
  return next({ ctx: { ...ctx, db: ctx.db, userId } });
});

// Middleware for project ownership verification
const hasProjectAccess = t.middleware(async ({ ctx, next }) => {
  if (!ctx.projectId) {
    throw new TRPCError({ code: 'FORBIDDEN', message: 'Project access required' });
  }
  if (!ctx.clerkUserId) {
    throw new TRPCError({ code: 'UNAUTHORIZED', message: 'User not authenticated' });
  }
  if (!ctx.db) {
    throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Database not available' });
  }
  const { users } = await import('../../src/db/schema');
  const userRows = await ctx.db.select({ id: users.id, clerkId: users.clerkId })
    .from(users)
    .where(eq(users.clerkId, ctx.clerkUserId));
  const dbUser = userRows[0];
  if (!dbUser) {
    throw new TRPCError({ code: 'FORBIDDEN', message: 'User mapping not found' });
  }
  const rows = await ctx.db.select({ id: projects.id, ownerId: projects.ownerId })
    .from(projects)
    .where(eq(projects.id, ctx.projectId));
  const project = rows[0];
  if (!project) {
    throw new TRPCError({ code: 'NOT_FOUND', message: `Project ${ctx.projectId} not found` });
  }
  if (project.ownerId === dbUser.id) {
    return next({ ctx: { ...ctx, projectId: ctx.projectId, userId: dbUser.id } });
  }
  // L3 fix: also check project membership
  const memberRows = await ctx.db.select()
    .from(projectMembers)
    .where(and(eq(projectMembers.projectId, ctx.projectId), eq(projectMembers.userId, dbUser.id)));
  if (memberRows.length === 0) {
    throw new TRPCError({ code: 'FORBIDDEN', message: `You do not have access to project ${ctx.projectId}` });
  }
  return next({ ctx: { ...ctx, projectId: ctx.projectId, userId: dbUser.id } });
});

// Base router
export const baseRouter = t.router;

// Procedure builders
export const publicProcedure = t.procedure.use(hasDb);
export const protectedProcedure = t.procedure.use(isAuthenticated).use(hasDb);

export const projectProcedure = t.procedure
  .use(isAuthenticated)
  .use(hasDb)
  .use(hasProjectAccess);

// Validation middleware
export const validateInput = <T extends z.ZodTypeAny>(schema: T) => {
  return t.middleware(({ input, next }) => {
    const validated = schema.parse(input);
    return next({ input: validated });
  });
};

export { t, TRPCError };
