import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { router, publicProcedure } from '../trpc'
import { CompetitionCategory, OceanIssue, TeamMemberRole } from '@prisma/client'
import {
  createNotification,
  notifyAdmins,
  NotificationTypes,
} from '../services/in-app-notification'

// Zod schemas for the application form
const teamMemberSchema = z.object({
  name: z.string().min(1, 'Name is required'),
  email: z.string().email('Invalid email address'),
  role: z.nativeEnum(TeamMemberRole).default('MEMBER'),
  title: z.string().optional(),
})

const applicationSchema = z.object({
  // Step 1: Category
  competitionCategory: z.nativeEnum(CompetitionCategory),

  // Step 2: Contact Info
  contactName: z.string().min(2, 'Full name is required'),
  contactEmail: z.string().email('Invalid email address'),
  contactPhone: z.string().min(5, 'Phone number is required'),
  country: z.string().min(2, 'Country is required'),
  city: z.string().optional(),

  // Step 3: Project Details
  projectName: z.string().min(2, 'Project name is required').max(200),
  teamName: z.string().optional(),
  description: z.string().min(20, 'Description must be at least 20 characters'),
  oceanIssue: z.nativeEnum(OceanIssue),

  // Step 4: Team Members
  teamMembers: z.array(teamMemberSchema).optional(),

  // Step 5: Additional Info (conditional & optional)
  institution: z.string().optional(), // Required if BUSINESS_CONCEPT
  startupCreatedDate: z.string().optional(), // Required if STARTUP
  wantsMentorship: z.boolean().default(false),
  referralSource: z.string().optional(),

  // Consent
  gdprConsent: z.boolean().refine((val) => val === true, {
    message: 'You must agree to the data processing terms',
  }),
})

export type ApplicationFormData = z.infer<typeof applicationSchema>

export const applicationRouter = router({
  /**
   * Get application configuration for a round
   */
  getConfig: publicProcedure
    .input(z.object({ roundSlug: z.string() }))
    .query(async ({ ctx, input }) => {
      const round = await ctx.prisma.round.findFirst({
        where: { slug: input.roundSlug },
        include: {
          program: {
            select: {
              id: true,
              name: true,
              year: true,
              description: true,
            },
          },
        },
      })

      if (!round) {
        throw new TRPCError({
          code: 'NOT_FOUND',
          message: 'Application round not found',
        })
      }

      // Check if submissions are open
      const now = new Date()
      let isOpen = false

      if (round.submissionStartDate && round.submissionEndDate) {
        isOpen = now >= round.submissionStartDate && now <= round.submissionEndDate
      } else if (round.submissionDeadline) {
        isOpen = now <= round.submissionDeadline
      } else {
        isOpen = round.status === 'ACTIVE'
      }

      // Calculate grace period if applicable
      let gracePeriodEnd: Date | null = null
      if (round.lateSubmissionGrace && round.submissionEndDate) {
        gracePeriodEnd = new Date(round.submissionEndDate.getTime() + round.lateSubmissionGrace * 60 * 60 * 1000)
        if (now <= gracePeriodEnd) {
          isOpen = true
        }
      }

      return {
        round: {
          id: round.id,
          name: round.name,
          slug: round.slug,
          submissionStartDate: round.submissionStartDate,
          submissionEndDate: round.submissionEndDate,
          submissionDeadline: round.submissionDeadline,
          lateSubmissionGrace: round.lateSubmissionGrace,
          gracePeriodEnd,
          phase1Deadline: round.phase1Deadline,
          phase2Deadline: round.phase2Deadline,
          isOpen,
        },
        program: round.program,
        oceanIssueOptions: [
          { value: 'POLLUTION_REDUCTION', label: 'Reduction of pollution (plastics, chemicals, noise, light,...)' },
          { value: 'CLIMATE_MITIGATION', label: 'Mitigation of climate change and sea-level rise' },
          { value: 'TECHNOLOGY_INNOVATION', label: 'Technology & innovations' },
          { value: 'SUSTAINABLE_SHIPPING', label: 'Sustainable shipping & yachting' },
          { value: 'BLUE_CARBON', label: 'Blue carbon' },
          { value: 'HABITAT_RESTORATION', label: 'Restoration of marine habitats & ecosystems' },
          { value: 'COMMUNITY_CAPACITY', label: 'Capacity building for coastal communities' },
          { value: 'SUSTAINABLE_FISHING', label: 'Sustainable fishing and aquaculture & blue food' },
          { value: 'CONSUMER_AWARENESS', label: 'Consumer awareness and education' },
          { value: 'OCEAN_ACIDIFICATION', label: 'Mitigation of ocean acidification' },
          { value: 'OTHER', label: 'Other' },
        ],
        competitionCategories: [
          {
            value: 'BUSINESS_CONCEPT',
            label: 'Business Concepts',
            description: 'For students and recent graduates with innovative ocean-focused business ideas',
          },
          {
            value: 'STARTUP',
            label: 'Start-ups',
            description: 'For established companies working on ocean protection solutions',
          },
        ],
      }
    }),

  /**
   * Submit a new application
   */
  submit: publicProcedure
    .input(
      z.object({
        roundId: z.string(),
        data: applicationSchema,
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { roundId, data } = input

      // Verify round exists and is open
      const round = await ctx.prisma.round.findUniqueOrThrow({
        where: { id: roundId },
        include: { program: true },
      })

      const now = new Date()

      // Check submission window
      let isOpen = false
      if (round.submissionStartDate && round.submissionEndDate) {
        isOpen = now >= round.submissionStartDate && now <= round.submissionEndDate

        // Check grace period
        if (!isOpen && round.lateSubmissionGrace) {
          const gracePeriodEnd = new Date(
            round.submissionEndDate.getTime() + round.lateSubmissionGrace * 60 * 60 * 1000
          )
          isOpen = now <= gracePeriodEnd
        }
      } else if (round.submissionDeadline) {
        isOpen = now <= round.submissionDeadline
      } else {
        isOpen = round.status === 'ACTIVE'
      }

      if (!isOpen) {
        throw new TRPCError({
          code: 'BAD_REQUEST',
          message: 'Applications are currently closed for this round',
        })
      }

      // Check if email already submitted for this round
      const existingProject = await ctx.prisma.project.findFirst({
        where: {
          roundId,
          submittedByEmail: data.contactEmail,
        },
      })

      if (existingProject) {
        throw new TRPCError({
          code: 'CONFLICT',
          message: 'An application with this email already exists for this round',
        })
      }

      // Check if user exists, or create a new applicant user
      let user = await ctx.prisma.user.findUnique({
        where: { email: data.contactEmail },
      })

      if (!user) {
        user = await ctx.prisma.user.create({
          data: {
            email: data.contactEmail,
            name: data.contactName,
            role: 'APPLICANT',
            status: 'ACTIVE',
            phoneNumber: data.contactPhone,
          },
        })
      }

      // Create the project
      const project = await ctx.prisma.project.create({
        data: {
          roundId,
          title: data.projectName,
          teamName: data.teamName,
          description: data.description,
          competitionCategory: data.competitionCategory,
          oceanIssue: data.oceanIssue,
          country: data.country,
          geographicZone: data.city ? `${data.city}, ${data.country}` : data.country,
          institution: data.institution,
          wantsMentorship: data.wantsMentorship,
          referralSource: data.referralSource,
          submissionSource: 'PUBLIC_FORM',
          submittedByEmail: data.contactEmail,
          submittedByUserId: user.id,
          submittedAt: now,
          metadataJson: {
            contactPhone: data.contactPhone,
            startupCreatedDate: data.startupCreatedDate,
            gdprConsentAt: now.toISOString(),
          },
        },
      })

      // Create team lead membership
      await ctx.prisma.teamMember.create({
        data: {
          projectId: project.id,
          userId: user.id,
          role: 'LEAD',
          title: 'Team Lead',
        },
      })

      // Create additional team members
      if (data.teamMembers && data.teamMembers.length > 0) {
        for (const member of data.teamMembers) {
          // Find or create user for team member
          let memberUser = await ctx.prisma.user.findUnique({
            where: { email: member.email },
          })

          if (!memberUser) {
            memberUser = await ctx.prisma.user.create({
              data: {
                email: member.email,
                name: member.name,
                role: 'APPLICANT',
                status: 'INVITED',
              },
            })
          }

          // Create team membership
          await ctx.prisma.teamMember.create({
            data: {
              projectId: project.id,
              userId: memberUser.id,
              role: member.role,
              title: member.title,
            },
          })
        }
      }

      // Create audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: user.id,
          action: 'CREATE',
          entityType: 'Project',
          entityId: project.id,
          detailsJson: {
            source: 'public_application_form',
            title: data.projectName,
            category: data.competitionCategory,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      // Notify applicant of successful submission
      await createNotification({
        userId: user.id,
        type: NotificationTypes.APPLICATION_SUBMITTED,
        title: 'Application Received',
        message: `Your application for "${data.projectName}" has been successfully submitted to ${round.program.name}.`,
        linkUrl: `/team/projects/${project.id}`,
        linkLabel: 'View Application',
        metadata: {
          projectName: data.projectName,
          programName: round.program.name,
        },
      })

      // Notify admins of new application
      await notifyAdmins({
        type: NotificationTypes.NEW_APPLICATION,
        title: 'New Application',
        message: `New application received: "${data.projectName}" from ${data.contactName}.`,
        linkUrl: `/admin/projects/${project.id}`,
        linkLabel: 'Review Application',
        metadata: {
          projectName: data.projectName,
          applicantName: data.contactName,
          applicantEmail: data.contactEmail,
          programName: round.program.name,
        },
      })

      return {
        success: true,
        projectId: project.id,
        message: `Thank you for applying to ${round.program.name} ${round.program.year}! We will review your application and contact you at ${data.contactEmail}.`,
      }
    }),

  /**
   * Check if email is already registered for a round
   */
  checkEmailAvailability: publicProcedure
    .input(
      z.object({
        roundId: z.string(),
        email: z.string().email(),
      })
    )
    .query(async ({ ctx, input }) => {
      const existing = await ctx.prisma.project.findFirst({
        where: {
          roundId: input.roundId,
          submittedByEmail: input.email,
        },
      })

      return {
        available: !existing,
        message: existing
          ? 'An application with this email already exists for this round'
          : null,
      }
    }),
})
