import { initTRPC, TRPCError } from '@trpc/server'
import superjson from 'superjson'
import { ZodError } from 'zod'
import type { Context } from './context'
import type { UserRole } from '@prisma/client'

/**
 * Initialize tRPC with context type and configuration
 */
const t = initTRPC.context<Context>().create({
  transformer: superjson,
  errorFormatter({ shape, error }) {
    return {
      ...shape,
      data: {
        ...shape.data,
        zodError:
          error.cause instanceof ZodError ? error.cause.flatten() : null,
      },
    }
  },
})

/**
 * Export reusable router and procedure helpers
 */
export const router = t.router
export const publicProcedure = t.procedure
export const middleware = t.middleware
export const createCallerFactory = t.createCallerFactory

// =============================================================================
// Middleware
// =============================================================================

/**
 * Middleware to require authenticated user
 */
const isAuthenticated = middleware(async ({ ctx, next }) => {
  if (!ctx.session?.user) {
    throw new TRPCError({
      code: 'UNAUTHORIZED',
      message: 'You must be logged in to perform this action',
    })
  }

  return next({
    ctx: {
      ...ctx,
      user: ctx.session.user,
    },
  })
})

/**
 * Middleware to require specific role(s)
 */
const hasRole = (...roles: UserRole[]) =>
  middleware(async ({ ctx, next }) => {
    if (!ctx.session?.user) {
      throw new TRPCError({
        code: 'UNAUTHORIZED',
        message: 'You must be logged in to perform this action',
      })
    }

    if (!roles.includes(ctx.session.user.role)) {
      throw new TRPCError({
        code: 'FORBIDDEN',
        message: 'You do not have permission to perform this action',
      })
    }

    return next({
      ctx: {
        ...ctx,
        user: ctx.session.user,
      },
    })
  })

/**
 * Middleware for audit logging
 */
const withAuditLog = middleware(async ({ ctx, next, path }) => {
  const result = await next()

  // Log successful mutations
  if (result.ok && path.includes('.')) {
    const [, action] = path.split('.')
    const mutationActions = ['create', 'update', 'delete', 'import', 'submit', 'grant', 'revoke']

    if (mutationActions.some((a) => action?.toLowerCase().includes(a))) {
      // Audit logging would happen here
      // We'll implement this in the audit service
    }
  }

  return result
})

// =============================================================================
// Procedure Types
// =============================================================================

/**
 * Protected procedure - requires authenticated user
 */
export const protectedProcedure = t.procedure.use(isAuthenticated)

/**
 * Admin procedure - requires SUPER_ADMIN or PROGRAM_ADMIN role
 */
export const adminProcedure = t.procedure.use(
  hasRole('SUPER_ADMIN', 'PROGRAM_ADMIN')
)

/**
 * Super admin procedure - requires SUPER_ADMIN role
 */
export const superAdminProcedure = t.procedure.use(hasRole('SUPER_ADMIN'))

/**
 * Jury procedure - requires JURY_MEMBER role
 */
export const juryProcedure = t.procedure.use(hasRole('JURY_MEMBER'))

/**
 * Mentor procedure - requires MENTOR role (or admin)
 */
export const mentorProcedure = t.procedure.use(
  hasRole('SUPER_ADMIN', 'PROGRAM_ADMIN', 'MENTOR')
)

/**
 * Observer procedure - requires OBSERVER role (read-only access)
 */
export const observerProcedure = t.procedure.use(
  hasRole('SUPER_ADMIN', 'PROGRAM_ADMIN', 'OBSERVER')
)

/**
 * Protected procedure with audit logging
 */
export const auditedProcedure = t.procedure
  .use(isAuthenticated)
  .use(withAuditLog)
