import {
  PrismaClient,
  UserRole,
  UserStatus,
  ProgramStatus,
  SettingType,
  SettingCategory,
  CompetitionCategory,
  OceanIssue,
  ProjectStatus,
  SubmissionSource,
  // Competition architecture enums
  CompetitionStatus,
  RoundType,
  RoundStatus,
  CapMode,
  JuryGroupMemberRole,
} from '@prisma/client'
import bcrypt from 'bcryptjs'
// Inline default configs so seed has ZERO dependency on src/ (not available in Docker prod image)
function defaultRoundConfig(roundType: RoundType): Record<string, unknown> {
  const defaults: Record<RoundType, () => Record<string, unknown>> = {
    INTAKE: () => ({
      allowDrafts: true, draftExpiryDays: 30,
      acceptedCategories: ['STARTUP', 'BUSINESS_CONCEPT'],
      maxFileSizeMB: 50, maxFilesPerSlot: 1, allowedMimeTypes: ['application/pdf'],
      lateSubmissionNotification: true, publicFormEnabled: false, customFields: [],
    }),
    FILTERING: () => ({
      rules: [], aiScreeningEnabled: true, manualReviewEnabled: true,
      aiConfidenceThresholds: { high: 0.85, medium: 0.6, low: 0.4 },
      autoAdvanceEligible: false, duplicateDetectionEnabled: true, batchSize: 20,
    }),
    EVALUATION: () => ({
      requiredReviewsPerProject: 3, scoringMode: 'criteria', requireFeedback: true,
      feedbackMinLength: 0, requireAllCriteriaScored: true, coiRequired: true,
      peerReviewEnabled: false, anonymizationLevel: 'fully_anonymous',
      aiSummaryEnabled: false, generateAiShortlist: false, advancementMode: 'admin_selection',
    }),
    SUBMISSION: () => ({
      eligibleStatuses: ['PASSED'], notifyEligibleTeams: true, lockPreviousWindows: true,
    }),
    MENTORING: () => ({
      eligibility: 'requested_only', chatEnabled: true, fileUploadEnabled: true,
      fileCommentsEnabled: true, filePromotionEnabled: true, autoAssignMentors: false,
    }),
    LIVE_FINAL: () => ({
      juryVotingEnabled: true, votingMode: 'simple', audienceVotingEnabled: false,
      audienceVoteWeight: 0, audienceVotingMode: 'per_project', audienceMaxFavorites: 3,
      audienceRequireIdentification: false, audienceRevealTiming: 'at_deliberation',
      deliberationEnabled: false, deliberationDurationMinutes: 30, showAudienceVotesToJury: false,
      presentationOrderMode: 'manual', presentationDurationMinutes: 15, qaDurationMinutes: 5,
      revealPolicy: 'ceremony',
    }),
    DELIBERATION: () => ({
      juryGroupId: 'PLACEHOLDER', mode: 'SINGLE_WINNER_VOTE',
      showCollectiveRankings: false, showPriorJuryData: false,
      tieBreakMethod: 'ADMIN_DECIDES', votingDuration: 60, topN: 3, allowAdminOverride: true,
    }),
  }
  return defaults[roundType]()
}
import { readFileSync } from 'fs'
import { parse } from 'csv-parse/sync'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const prisma = new PrismaClient()

// =============================================================================
// CSV Column Mapping Helpers
// =============================================================================

const categoryMap: Record<string, CompetitionCategory> = {
  'the « Start-ups » category': CompetitionCategory.STARTUP,
  'the « Business concepts » category': CompetitionCategory.BUSINESS_CONCEPT,
}

const issueMap: Record<string, OceanIssue> = {
  'Reduction of pollution': OceanIssue.POLLUTION_REDUCTION,
  'Mitigation of climate change': OceanIssue.CLIMATE_MITIGATION,
  'Technology & innovations': OceanIssue.TECHNOLOGY_INNOVATION,
  'Sustainable shipping': OceanIssue.SUSTAINABLE_SHIPPING,
  'Blue Carbon': OceanIssue.BLUE_CARBON,
  'Restoration of marine': OceanIssue.HABITAT_RESTORATION,
  'Capacity building': OceanIssue.COMMUNITY_CAPACITY,
  'Sustainable fishing': OceanIssue.SUSTAINABLE_FISHING,
  'Consumer awareness': OceanIssue.CONSUMER_AWARENESS,
  'Mitigation of ocean acidification': OceanIssue.OCEAN_ACIDIFICATION,
  'Other': OceanIssue.OTHER,
}

function normalizeSpaces(s: string): string {
  // Replace non-breaking spaces (U+00A0) and other whitespace variants with regular spaces
  return s.replace(/\u00A0/g, ' ')
}

function mapCategory(raw: string | undefined): CompetitionCategory | null {
  if (!raw) return null
  const trimmed = normalizeSpaces(raw.trim())
  for (const [prefix, value] of Object.entries(categoryMap)) {
    if (trimmed.startsWith(prefix)) return value
  }
  return null
}

function mapIssue(raw: string | undefined): OceanIssue | null {
  if (!raw) return null
  const trimmed = normalizeSpaces(raw.trim())
  for (const [prefix, value] of Object.entries(issueMap)) {
    if (trimmed.startsWith(prefix)) return value
  }
  return OceanIssue.OTHER
}

function parseFoundedDate(raw: string | undefined): Date | null {
  if (!raw) return null
  const trimmed = raw.trim()
  if (!trimmed) return null
  const d = new Date(trimmed)
  return isNaN(d.getTime()) ? null : d
}

function isEmptyRow(row: Record<string, string>): boolean {
  const name = (row['Full name'] || '').trim()
  const email = (row['E-mail'] || '').trim()
  const project = (row["Project's name"] || '').trim()
  return !name && !email && !project
}

// =============================================================================
// Main Seed Function
// =============================================================================

async function main() {
  console.log('🌱 Seeding database with MOPC 2026 real data...\n')

  // ==========================================================================
  // 1. System Settings
  // ==========================================================================
  console.log('📋 Creating system settings...')

  const settings = [
    { key: 'ai_enabled', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.AI, description: 'Enable AI-powered jury assignment suggestions' },
    { key: 'ai_provider', value: 'openai', type: SettingType.STRING, category: SettingCategory.AI, description: 'AI provider for smart assignment (openai)' },
    { key: 'ai_model', value: 'gpt-4o', type: SettingType.STRING, category: SettingCategory.AI, description: 'OpenAI model to use for suggestions' },
    { key: 'ai_send_descriptions', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.AI, description: 'Send anonymized project descriptions to AI' },
    { key: 'platform_name', value: 'Monaco Ocean Protection Challenge', type: SettingType.STRING, category: SettingCategory.BRANDING, description: 'Platform display name' },
    { key: 'primary_color', value: '#de0f1e', type: SettingType.STRING, category: SettingCategory.BRANDING, description: 'Primary brand color (hex)' },
    { key: 'secondary_color', value: '#053d57', type: SettingType.STRING, category: SettingCategory.BRANDING, description: 'Secondary brand color (hex)' },
    { key: 'accent_color', value: '#557f8c', type: SettingType.STRING, category: SettingCategory.BRANDING, description: 'Accent color (hex)' },
    { key: 'session_duration_hours', value: '24', type: SettingType.NUMBER, category: SettingCategory.SECURITY, description: 'Session duration in hours' },
    { key: 'magic_link_expiry_minutes', value: '15', type: SettingType.NUMBER, category: SettingCategory.SECURITY, description: 'Magic link expiry time in minutes' },
    { key: 'rate_limit_requests_per_minute', value: '60', type: SettingType.NUMBER, category: SettingCategory.SECURITY, description: 'API rate limit per minute' },
    { key: 'storage_provider', value: 's3', type: SettingType.STRING, category: SettingCategory.STORAGE, description: 'Storage provider: s3 (MinIO) or local (filesystem)' },
    { key: 'local_storage_path', value: './uploads', type: SettingType.STRING, category: SettingCategory.STORAGE, description: 'Base path for local file storage' },
    { key: 'max_file_size_mb', value: '500', type: SettingType.NUMBER, category: SettingCategory.STORAGE, description: 'Maximum file upload size in MB' },
    { key: 'avatar_max_size_mb', value: '5', type: SettingType.NUMBER, category: SettingCategory.STORAGE, description: 'Maximum avatar image size in MB' },
    { key: 'allowed_file_types', value: JSON.stringify(['application/pdf', 'video/mp4', 'video/quicktime', 'image/png', 'image/jpeg']), type: SettingType.JSON, category: SettingCategory.STORAGE, description: 'Allowed MIME types for file uploads' },
    { key: 'allowed_image_types', value: JSON.stringify(['image/png', 'image/jpeg', 'image/webp']), type: SettingType.JSON, category: SettingCategory.STORAGE, description: 'Allowed MIME types for avatar/logo uploads' },
    { key: 'default_timezone', value: 'Europe/Monaco', type: SettingType.STRING, category: SettingCategory.DEFAULTS, description: 'Default timezone for date displays' },
    { key: 'default_page_size', value: '20', type: SettingType.NUMBER, category: SettingCategory.DEFAULTS, description: 'Default pagination size' },
    { key: 'autosave_interval_seconds', value: '30', type: SettingType.NUMBER, category: SettingCategory.DEFAULTS, description: 'Autosave interval for evaluation forms' },
    { key: 'whatsapp_enabled', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.WHATSAPP, description: 'Enable WhatsApp notifications' },
    { key: 'whatsapp_provider', value: 'META', type: SettingType.STRING, category: SettingCategory.WHATSAPP, description: 'WhatsApp provider (META or TWILIO)' },
    { key: 'openai_api_key', value: '', type: SettingType.SECRET, category: SettingCategory.AI, description: 'OpenAI API Key for AI-powered features', isSecret: true },
  ]

  for (const setting of settings) {
    await prisma.systemSettings.upsert({
      where: { key: setting.key },
      update: {},
      create: setting,
    })
  }
  console.log(`   Created ${settings.length} settings`)

  // ==========================================================================
  // 1b. Expertise Tags
  // ==========================================================================
  console.log('\n🏷️  Creating expertise tags...')

  const tagGroups = [
    {
      category: 'Pollution Reduction',
      color: '#dc2626',
      tags: [
        { name: 'Marine Plastic & Ghost Gear Cleanup', description: 'Collection and processing of plastic waste, fishing nets, and marine debris from coastal and ocean environments' },
        { name: 'Industrial & Wastewater Marine Protection', description: 'Systems reducing chemical discharge, nutrient runoff, and wastewater pollution before ocean impact' },
        { name: 'Circular Materials from Marine Waste', description: 'Transformation of algae, fishery byproducts, and recovered ocean waste into useful products' },
      ],
    },
    {
      category: 'Climate Mitigation',
      color: '#0284c7',
      tags: [
        { name: 'Low-Carbon Blue Supply Chains', description: 'Solutions reducing emissions in seafood logistics, cooling, and marine value chains' },
        { name: 'Ocean Renewable Energy', description: 'Wave, tidal, offshore, and hybrid marine energy technologies' },
        { name: 'Marine Carbon Removal & Sequestration', description: 'Approaches that remove and store carbon through ocean-linked biological or mineral pathways' },
      ],
    },
    {
      category: 'Technology & Innovation',
      color: '#7c3aed',
      tags: [
        { name: 'Marine Robotics & Autonomous Systems', description: 'ROVs, AUVs, and marine drones used for restoration, monitoring, and intervention' },
        { name: 'AI Ocean Intelligence', description: 'Machine learning and advanced analytics for ocean health, biodiversity, or operations optimization' },
        { name: 'Marine Ecotoxicology & Environmental Testing', description: 'Testing platforms that evaluate product or discharge impacts on marine ecosystems' },
      ],
    },
    {
      category: 'Sustainable Shipping',
      color: '#053d57',
      tags: [
        { name: 'Cleaner Maritime Operations', description: 'Operational innovations that reduce emissions, waste, and fuel intensity in maritime transport' },
        { name: 'Port Environmental Performance', description: 'Technologies and practices that improve sustainability outcomes in ports and harbors' },
        { name: 'Marine Noise & Vessel Impact Reduction', description: 'Solutions that mitigate underwater noise and ecological disturbance from vessel activity' },
      ],
    },
    {
      category: 'Blue Carbon',
      color: '#0ea5a4',
      tags: [
        { name: 'Seagrass & Mangrove Carbon Projects', description: 'Restoration and protection programs for key blue carbon habitats' },
        { name: 'Blue Carbon Measurement & Verification', description: 'Monitoring and MRV tools for quantifying carbon outcomes in marine ecosystems' },
        { name: 'Financing Blue Carbon Conservation', description: 'Financial models enabling scalable protection and restoration of blue carbon assets' },
      ],
    },
    {
      category: 'Habitat Restoration',
      color: '#16a34a',
      tags: [
        { name: 'Coral Restoration & Reef Resilience', description: 'Propagation, outplanting, and resilience strategies for coral ecosystems' },
        { name: 'Coastal Habitat Regeneration', description: 'Recovery of dunes, wetlands, estuaries, and nearshore biodiversity hotspots' },
        { name: 'Biodiversity Threat Mitigation', description: 'Targeted interventions for invasive species, habitat degradation, and species decline' },
      ],
    },
    {
      category: 'Community Capacity',
      color: '#ea580c',
      tags: [
        { name: 'Coastal Livelihood & Inclusion Models', description: 'Community-led business models that improve income while protecting marine ecosystems' },
        { name: 'Women-Led Blue Economy Initiatives', description: 'Programs that strengthen women leadership and participation in sustainable marine enterprises' },
        { name: 'Ocean Skills & Entrepreneurship Training', description: 'Capacity-building and startup enablement for students and coastal entrepreneurs' },
      ],
    },
    {
      category: 'Sustainable Fishing',
      color: '#059669',
      tags: [
        { name: 'Regenerative Aquaculture', description: 'Aquaculture systems integrating ecological restoration, animal welfare, and reduced environmental pressure' },
        { name: 'Seaweed & Algae Value Chains', description: 'Cultivation and commercialization of algae or seaweed for food, feed, and biomaterials' },
        { name: 'Cold Chain & Post-Harvest Seafood Efficiency', description: 'Technologies reducing fish loss and waste through sustainable preservation and handling' },
      ],
    },
    {
      category: 'Consumer Awareness',
      color: '#f59e0b',
      tags: [
        { name: 'Ocean Literacy Platforms', description: 'Digital or physical tools that increase public understanding of ocean health issues' },
        { name: 'Behavior Change for Ocean Protection', description: 'Campaigns and products that help consumers reduce harmful marine impact' },
        { name: 'Traceability & Sustainable Choice Tools', description: 'Interfaces helping buyers identify responsible seafood and ocean-positive products' },
      ],
    },
    {
      category: 'Ocean Acidification',
      color: '#2563eb',
      tags: [
        { name: 'Acidification Monitoring & Forecasting', description: 'Sensors and models tracking pH dynamics and acidification risk in marine environments' },
        { name: 'Alkalinity & Buffering Interventions', description: 'Interventions designed to reduce acidification pressure on vulnerable marine systems' },
        { name: 'Acidification-Resilient Aquaculture', description: 'Farming approaches and species strategies resilient to changing ocean chemistry' },
      ],
    },
  ] as const

  const expertiseTags = tagGroups.flatMap((group, groupIndex) =>
    group.tags.map((tag, tagIndex) => ({
      name: tag.name,
      description: tag.description,
      category: group.category,
      color: group.color,
      sortOrder: groupIndex * 10 + tagIndex,
    }))
  )

  for (const tag of expertiseTags) {
    await prisma.expertiseTag.upsert({
      where: { name: tag.name },
      update: {
        description: tag.description,
        category: tag.category,
        color: tag.color,
        sortOrder: tag.sortOrder,
        isActive: true,
      },
      create: {
        name: tag.name,
        description: tag.description,
        category: tag.category,
        color: tag.color,
        sortOrder: tag.sortOrder,
        isActive: true,
      },
    })
  }
  console.log(`   Created ${expertiseTags.length} expertise tags across ${new Set(expertiseTags.map(t => t.category)).size} categories`)

  // ==========================================================================
  // 2. Admin/Staff Users
  // ==========================================================================
  console.log('\n👤 Creating admin & staff users...')

  const staffAccounts = [
    { email: 'matt@monaco-opc.com', name: 'Matt', role: UserRole.SUPER_ADMIN, password: '195260Mp!' },
    { email: 'matt@letsbe.solutions', name: 'Matt (Applicant)', role: UserRole.APPLICANT, password: '195260Mp!' },
    { email: 'admin@monaco-opc.com', name: 'Admin', role: UserRole.PROGRAM_ADMIN, password: 'Admin123!' },
  ]

  const staffUsers: Record<string, string> = {}
  for (const account of staffAccounts) {
    const passwordHash = await bcrypt.hash(account.password, 12)
    const needsPassword = account.role === UserRole.SUPER_ADMIN || account.role === UserRole.APPLICANT
    const user = await prisma.user.upsert({
      where: { email: account.email },
      update: needsPassword
        ? {
            status: UserStatus.ACTIVE,
            passwordHash,
            mustSetPassword: false,
            passwordSetAt: new Date(),
            onboardingCompletedAt: new Date(),
          }
        : {
            status: UserStatus.NONE,
            passwordHash: null,
            mustSetPassword: true,
            passwordSetAt: null,
            onboardingCompletedAt: null,
            inviteToken: null,
            inviteTokenExpiresAt: null,
          },
      create: {
        email: account.email,
        name: account.name,
        role: account.role,
        roles: [account.role],
        status: needsPassword ? UserStatus.ACTIVE : UserStatus.NONE,
        passwordHash: needsPassword ? passwordHash : null,
        mustSetPassword: !needsPassword,
        passwordSetAt: needsPassword ? new Date() : null,
        onboardingCompletedAt: needsPassword ? new Date() : null,
      },
    })
    staffUsers[account.email] = user.id
    console.log(`   ✓ ${account.role}: ${account.email}`)
  }

  // ==========================================================================
  // 3. Jury Members (8 fictional)
  // ==========================================================================
  console.log('\n⚖️  Creating jury members...')

  const juryMembers = [
    { email: 'jury1@monaco-opc.com', name: 'Dr. Sophie Laurent', country: 'France', tags: ['marine-biology', 'coral-restoration', 'biodiversity'] },
    { email: 'jury2@monaco-opc.com', name: 'Prof. Marco Bianchi', country: 'Italy', tags: ['ocean-engineering', 'renewable-energy', 'desalination'] },
    { email: 'jury3@monaco-opc.com', name: 'Dr. Aisha Patel', country: 'United Kingdom', tags: ['sustainability', 'circular-economy', 'waste-management'] },
    { email: 'jury4@monaco-opc.com', name: 'Dr. Kenji Tanaka', country: 'Japan', tags: ['aquaculture', 'sustainable-fishing', 'marine-technology'] },
    { email: 'jury5@monaco-opc.com', name: 'Prof. Elena Volkov', country: 'Germany', tags: ['climate-science', 'ocean-acidification', 'blue-carbon'] },
    { email: 'jury6@monaco-opc.com', name: 'Dr. Amara Diallo', country: 'Senegal', tags: ['community-development', 'capacity-building', 'coastal-management'] },
    { email: 'jury7@monaco-opc.com', name: 'Dr. Carlos Rivera', country: 'Spain', tags: ['blue-economy', 'maritime-policy', 'shipping'] },
    { email: 'jury8@monaco-opc.com', name: 'Prof. Lin Wei', country: 'Singapore', tags: ['marine-biotech', 'pollution-monitoring', 'AI-ocean'] },
  ]

  const juryUserIds: string[] = []
  for (const j of juryMembers) {
    const user = await prisma.user.upsert({
      where: { email: j.email },
      update: {
        status: UserStatus.NONE,
      },
      create: {
        email: j.email,
        name: j.name,
        role: UserRole.JURY_MEMBER,
        roles: [UserRole.JURY_MEMBER],
        status: UserStatus.NONE,
        country: j.country,
        expertiseTags: j.tags,
        bio: `Expert in ${j.tags.join(', ')}`,
      },
    })
    juryUserIds.push(user.id)
    console.log(`   ✓ Jury: ${j.name} (${j.country})`)
  }

  // ==========================================================================
  // 4. Mentors (3 fictional)
  // ==========================================================================
  console.log('\n🧑‍🏫 Creating mentors...')

  const mentors = [
    { email: 'mentor1@monaco-opc.com', name: 'Marie Dubois', country: 'Monaco', tags: ['startup-coaching', 'ocean-conservation'] },
    { email: 'mentor2@monaco-opc.com', name: 'James Cooper', country: 'United States', tags: ['venture-capital', 'cleantech'] },
    { email: 'mentor3@monaco-opc.com', name: 'Fatima Al-Rashid', country: 'UAE', tags: ['impact-investing', 'sustainability-strategy'] },
  ]

  for (const m of mentors) {
    await prisma.user.upsert({
      where: { email: m.email },
      update: {
        status: UserStatus.NONE,
      },
      create: {
        email: m.email,
        name: m.name,
        role: UserRole.MENTOR,
        roles: [UserRole.MENTOR],
        status: UserStatus.NONE,
        country: m.country,
        expertiseTags: m.tags,
      },
    })
    console.log(`   ✓ Mentor: ${m.name}`)
  }

  // ==========================================================================
  // 5. Observers (2 fictional)
  // ==========================================================================
  console.log('\n👁️  Creating observers...')

  const observers = [
    { email: 'observer1@monaco-opc.com', name: 'Pierre Martin', country: 'Monaco' },
    { email: 'observer2@monaco-opc.com', name: 'Sarah Chen', country: 'Canada' },
  ]

  for (const o of observers) {
    await prisma.user.upsert({
      where: { email: o.email },
      update: {
        status: UserStatus.NONE,
      },
      create: {
        email: o.email,
        name: o.name,
        role: UserRole.OBSERVER,
        roles: [UserRole.OBSERVER],
        status: UserStatus.NONE,
        country: o.country,
      },
    })
    console.log(`   ✓ Observer: ${o.name}`)
  }

  // ==========================================================================
  // 6. Program
  // ==========================================================================
  console.log('\n📁 Creating program...')

  const program = await prisma.program.upsert({
    where: { name_year: { name: 'Monaco Ocean Protection Challenge', year: 2026 } },
    update: {},
    create: {
      name: 'Monaco Ocean Protection Challenge',
      year: 2026,
      status: ProgramStatus.ACTIVE,
      description: 'Annual ocean conservation startup competition supporting innovative solutions for ocean protection.',
    },
  })
  console.log(`   ✓ Program: ${program.name} ${program.year}`)

  // Legacy Pipeline/Track/Stage system removed - Competition/Round architecture now in use

  // ==========================================================================
  // 7. Parse CSV & Create Applicants + Projects
  // ==========================================================================
  console.log('\n📄 Checking for existing projects...')

  const existingProjectCount = await prisma.project.count({ where: { programId: program.id } })
  let projectCount = 0

  if (existingProjectCount > 0) {
    projectCount = existingProjectCount
    console.log(`   ⏭️  ${existingProjectCount} projects already exist, skipping CSV import`)
  } else {
    console.log('   Parsing Candidatures2026.csv...')

    const csvPath = join(__dirname, '..', 'docs', 'Candidatures2026.csv')
    const csvContent = readFileSync(csvPath, 'utf-8')

    // Remove BOM if present
    const cleanContent = csvContent.replace(/^\uFEFF/, '')

    const records: Record<string, string>[] = parse(cleanContent, {
      columns: true,
      skip_empty_lines: true,
      relax_column_count: true,
      trim: true,
    })

    console.log(`   Raw CSV rows: ${records.length}`)

    // Skip only completely empty rows (no name, no email, no project)
    const validRecords = records.filter((row: Record<string, string>) => !isEmptyRow(row))
    console.log(`   Entries to seed: ${validRecords.length}`)

    // Create applicant users and projects
    console.log('\n🚀 Creating applicant users and projects...')

    let skippedNoEmail = 0
    for (let rowIdx = 0; rowIdx < validRecords.length; rowIdx++) {
      const row = validRecords[rowIdx]
      const email = (row['E-mail'] || '').trim().toLowerCase()
      const name = (row['Full name'] || '').trim()
      const phone = (row['Téléphone'] || '').trim() || null
      const country = (row['Country'] || '').trim() || null
      const zone = (row['Tri par zone'] || '').trim() || null
      const university = (row['University'] || '').trim() || null
      const projectName = (row["Project's name"] || '').trim()
      const teamMembers = (row['Team members'] || '').trim() || null
      const category = mapCategory(row['Category'])
      const issue = mapIssue(row['Issue'])
      const comment = (row['Comment'] || row['Comment '] || '').trim() || null
      const mentorship = (row['Mentorship'] || '').trim().toLowerCase() === 'true'
      const referral = (row['How did you hear about MOPC?'] || '').trim() || null
      const appStatus = (row['Application status'] || '').trim() || null
      const phase1Url = (row['PHASE 1 - Submission'] || '').trim() || null
      const phase2Url = (row['PHASE 2 - Submission'] || '').trim() || null
      const foundedAt = parseFoundedDate(row['Date of creation'])

      // Skip rows with no usable email (can't create user without one)
      if (!email || !email.includes('@')) {
        skippedNoEmail++
        console.log(`   ⚠ Row ${rowIdx + 2}: skipped (no valid email)`)
        continue
      }

      // Create or get applicant user (upsert handles duplicate emails)
      const user = await prisma.user.upsert({
        where: { email },
        update: {
          status: UserStatus.NONE,
          mustSetPassword: true,
        },
        create: {
          email,
          name: name || `Applicant ${rowIdx + 1}`,
          role: UserRole.APPLICANT,
          roles: [UserRole.APPLICANT],
          status: UserStatus.NONE,
          phoneNumber: phone,
          country,
          metadataJson: university ? { institution: university } : undefined,
          mustSetPassword: true,
        },
      })

      // Create project
      const createdProject = await prisma.project.create({
        data: {
          programId: program.id,
          title: projectName || `Project by ${name}`,
          description: comment,
          competitionCategory: category,
          oceanIssue: issue,
          country,
          geographicZone: zone,
          institution: university,
          wantsMentorship: mentorship,
          foundedAt,
          phase1SubmissionUrl: phase1Url,
          phase2SubmissionUrl: phase2Url,
          referralSource: referral,
          applicationStatus: appStatus,
          submissionSource: SubmissionSource.CSV,
          submittedByUserId: user.id,
          submittedByEmail: email,
          submittedAt: new Date(),
          status: ProjectStatus.SUBMITTED,
          metadataJson: teamMembers ? { teamMembers } : undefined,
        },
      })

      // Link submitter as team lead
      await prisma.teamMember.upsert({
        where: { projectId_userId: { projectId: createdProject.id, userId: user.id } },
        update: {},
        create: {
          projectId: createdProject.id,
          userId: user.id,
          role: 'LEAD',
        },
      })

      projectCount++
      if (projectCount % 50 === 0) {
        console.log(`   ... ${projectCount} projects created`)
      }
    }

    console.log(`   ✓ Created ${projectCount} projects (with team lead links)`)
    if (skippedNoEmail > 0) {
      console.log(`   ⚠ Skipped ${skippedNoEmail} rows with no valid email`)
    }
  }

  // Legacy evaluation forms and special awards removed - Competition/Round architecture now in use

  // ==========================================================================
  // 8. Competition Architecture
  // ==========================================================================
  console.log('\n🏗️  Creating competition architecture...')

  const competition = await prisma.competition.upsert({
    where: { slug: 'mopc-2026' },
    update: {},
    create: {
      programId: program.id,
      name: 'MOPC 2026',
      slug: 'mopc-2026',
      status: CompetitionStatus.ACTIVE,
      categoryMode: 'SHARED',
      startupFinalistCount: 3,
      conceptFinalistCount: 3,
      notifyOnRoundAdvance: true,
      notifyOnDeadlineApproach: true,
      deadlineReminderDays: [7, 3, 1],
    },
  })
  console.log(`   ✓ Competition: ${competition.name}`)

  // --- Jury Groups ---
  const juryGroup1 = await prisma.juryGroup.upsert({
    where: { competitionId_slug: { competitionId: competition.id, slug: 'screening-jury' } },
    update: {},
    create: {
      competitionId: competition.id,
      name: 'Screening Jury',
      slug: 'screening-jury',
      sortOrder: 0,
      defaultMaxAssignments: 30,
      defaultCapMode: CapMode.SOFT,
      softCapBuffer: 5,
      categoryQuotasEnabled: false,
    },
  })

  const juryGroup2 = await prisma.juryGroup.upsert({
    where: { competitionId_slug: { competitionId: competition.id, slug: 'expert-jury' } },
    update: {},
    create: {
      competitionId: competition.id,
      name: 'Expert Jury',
      slug: 'expert-jury',
      sortOrder: 1,
      defaultMaxAssignments: 20,
      defaultCapMode: CapMode.SOFT,
      softCapBuffer: 2,
      categoryQuotasEnabled: true,
      defaultCategoryQuotas: {
        STARTUP: { min: 5, max: 15 },
        BUSINESS_CONCEPT: { min: 3, max: 10 },
      },
    },
  })

  const juryGroup3 = await prisma.juryGroup.upsert({
    where: { competitionId_slug: { competitionId: competition.id, slug: 'finals-jury' } },
    update: {},
    create: {
      competitionId: competition.id,
      name: 'Finals Jury',
      slug: 'finals-jury',
      sortOrder: 2,
      defaultMaxAssignments: 10,
      defaultCapMode: CapMode.HARD,
      softCapBuffer: 0,
      categoryQuotasEnabled: false,
    },
  })

  console.log('   ✓ Jury Groups: Screening, Expert, Finals')

  // --- Add jury members to groups ---
  // Split 8 jurors: 4 in screening, 6 in expert (some overlap), all 8 in finals
  const juryGroupAssignments = [
    { groupId: juryGroup1.id, userIds: juryUserIds.slice(0, 4), role: JuryGroupMemberRole.MEMBER },
    { groupId: juryGroup2.id, userIds: juryUserIds.slice(0, 6), role: JuryGroupMemberRole.MEMBER },
    { groupId: juryGroup3.id, userIds: juryUserIds, role: JuryGroupMemberRole.MEMBER },
  ]

  let memberCount = 0
  for (const assignment of juryGroupAssignments) {
    for (let i = 0; i < assignment.userIds.length; i++) {
      const userId = assignment.userIds[i]
      await prisma.juryGroupMember.upsert({
        where: {
          juryGroupId_userId: { juryGroupId: assignment.groupId, userId },
        },
        update: {},
        create: {
          juryGroupId: assignment.groupId,
          userId,
          role: i === 0 ? JuryGroupMemberRole.CHAIR : assignment.role,
        },
      })
      memberCount++
    }
  }
  console.log(`   ✓ ${memberCount} jury group memberships created`)

  // --- Demo self-service preferences ---
  // Enable self-service on the Expert Panel and set preferences for first 2 members
  await prisma.juryGroup.update({
    where: { id: juryGroup2.id },
    data: { allowJurorCapAdjustment: true, allowJurorRatioAdjustment: true },
  })

  // Juror 0 sets a lower cap and prefers startups
  const selfServiceMember1 = await prisma.juryGroupMember.findUnique({
    where: { juryGroupId_userId: { juryGroupId: juryGroup2.id, userId: juryUserIds[0] } },
  })
  if (selfServiceMember1) {
    await prisma.juryGroupMember.update({
      where: { id: selfServiceMember1.id },
      data: { selfServiceCap: 12, selfServiceRatio: 0.7 },
    })
  }

  // Juror 1 sets a moderate ratio preference
  const selfServiceMember2 = await prisma.juryGroupMember.findUnique({
    where: { juryGroupId_userId: { juryGroupId: juryGroup2.id, userId: juryUserIds[1] } },
  })
  if (selfServiceMember2) {
    await prisma.juryGroupMember.update({
      where: { id: selfServiceMember2.id },
      data: { selfServiceRatio: 0.4 },
    })
  }
  console.log('   ✓ Self-service preferences: 2 jurors in Expert Panel')

  // --- Submission Windows ---
  const submissionWindow1 = await prisma.submissionWindow.upsert({
    where: { competitionId_slug: { competitionId: competition.id, slug: 'r1-application-docs' } },
    update: {},
    create: {
      competitionId: competition.id,
      name: 'R1 Application Documents',
      slug: 'r1-application-docs',
      roundNumber: 1,
      sortOrder: 0,
      windowOpenAt: new Date('2026-01-01'),
      windowCloseAt: new Date('2026-01-31'),
      isLocked: true,
    },
  })

  const submissionWindow2 = await prisma.submissionWindow.upsert({
    where: { competitionId_slug: { competitionId: competition.id, slug: 'r4-semifinal-docs' } },
    update: {},
    create: {
      competitionId: competition.id,
      name: 'R4 Semi-Finalist Documents',
      slug: 'r4-semifinal-docs',
      roundNumber: 4,
      sortOrder: 1,
      windowOpenAt: new Date('2026-04-01'),
      windowCloseAt: new Date('2026-04-30'),
      isLocked: false,
    },
  })

  console.log('   ✓ Submission Windows: R1 Application, R4 Semi-finalist')

  // --- File Requirements ---
  await prisma.submissionFileRequirement.upsert({
    where: { submissionWindowId_slug: { submissionWindowId: submissionWindow1.id, slug: 'executive-summary' } },
    update: {},
    create: {
      submissionWindowId: submissionWindow1.id,
      label: 'Executive Summary',
      slug: 'executive-summary',
      description: 'PDF document summarizing the project',
      mimeTypes: ['application/pdf'],
      maxSizeMb: 50,
      required: true,
      sortOrder: 0,
    },
  })

  await prisma.submissionFileRequirement.upsert({
    where: { submissionWindowId_slug: { submissionWindowId: submissionWindow1.id, slug: 'video-pitch' } },
    update: {},
    create: {
      submissionWindowId: submissionWindow1.id,
      label: 'Video Pitch',
      slug: 'video-pitch',
      description: 'Short video pitching the project (max 5 minutes)',
      mimeTypes: ['video/mp4', 'video/quicktime'],
      maxSizeMb: 500,
      required: false,
      sortOrder: 1,
    },
  })

  await prisma.submissionFileRequirement.upsert({
    where: { submissionWindowId_slug: { submissionWindowId: submissionWindow2.id, slug: 'updated-business-plan' } },
    update: {},
    create: {
      submissionWindowId: submissionWindow2.id,
      label: 'Updated Business Plan',
      slug: 'updated-business-plan',
      description: 'Updated business plan with financials',
      mimeTypes: ['application/pdf'],
      maxSizeMb: 50,
      required: true,
      sortOrder: 0,
    },
  })

  console.log('   ✓ File Requirements: Exec Summary, Video Pitch, Business Plan')

  // --- Rounds (8-round Monaco flow) ---
  const roundDefs = [
    { name: 'R1 - Application Intake', slug: 'r1-intake', roundType: RoundType.INTAKE, sortOrder: 0, status: RoundStatus.ROUND_CLOSED, juryGroupId: null, submissionWindowId: submissionWindow1.id },
    { name: 'R2 - AI Screening', slug: 'r2-screening', roundType: RoundType.FILTERING, sortOrder: 1, status: RoundStatus.ROUND_ACTIVE, juryGroupId: juryGroup1.id, submissionWindowId: null },
    { name: 'R3 - Expert Evaluation', slug: 'r3-evaluation', roundType: RoundType.EVALUATION, sortOrder: 2, status: RoundStatus.ROUND_DRAFT, juryGroupId: juryGroup2.id, submissionWindowId: null },
    { name: 'R4 - Document Submission', slug: 'r4-submission', roundType: RoundType.SUBMISSION, sortOrder: 3, status: RoundStatus.ROUND_DRAFT, juryGroupId: null, submissionWindowId: submissionWindow2.id },
    { name: 'R5 - Semi-Final Evaluation', slug: 'r5-semi-eval', roundType: RoundType.EVALUATION, sortOrder: 4, status: RoundStatus.ROUND_DRAFT, juryGroupId: juryGroup2.id, submissionWindowId: null },
    { name: 'R6 - Mentoring', slug: 'r6-mentoring', roundType: RoundType.MENTORING, sortOrder: 5, status: RoundStatus.ROUND_DRAFT, juryGroupId: null, submissionWindowId: null },
    { name: 'R7 - Grand Final', slug: 'r7-grand-final', roundType: RoundType.LIVE_FINAL, sortOrder: 6, status: RoundStatus.ROUND_DRAFT, juryGroupId: juryGroup3.id, submissionWindowId: null },
    { name: 'R8 - Deliberation', slug: 'r8-deliberation', roundType: RoundType.DELIBERATION, sortOrder: 7, status: RoundStatus.ROUND_DRAFT, juryGroupId: juryGroup3.id, submissionWindowId: null },
  ]

  const rounds = []
  for (const def of roundDefs) {
    const config = defaultRoundConfig(def.roundType)
    const round = await prisma.round.upsert({
      where: { competitionId_slug: { competitionId: competition.id, slug: def.slug } },
      update: {},
      create: {
        competitionId: competition.id,
        name: def.name,
        slug: def.slug,
        roundType: def.roundType,
        status: def.status,
        sortOrder: def.sortOrder,
        configJson: config as object,
        juryGroupId: def.juryGroupId,
        submissionWindowId: def.submissionWindowId,
      },
    })
    rounds.push(round)
  }
  console.log(`   ✓ ${rounds.length} rounds created (R1-R8)`)

  // --- Assign all projects to intake round (COMPLETED, since intake is closed) ---
  const intakeRound = rounds[0]
  const allProjects = await prisma.project.findMany({
    where: { programId: program.id },
    select: { id: true },
  })
  if (allProjects.length > 0) {
    await prisma.projectRoundState.createMany({
      data: allProjects.map((p) => ({
        projectId: p.id,
        roundId: intakeRound.id,
        state: 'COMPLETED' as const,
      })),
      skipDuplicates: true,
    })
    console.log(`   ✓ ${allProjects.length} projects assigned to intake round (COMPLETED)`)
  }

  // --- Round-Submission Visibility (which rounds can see which submission windows) ---
  // R2 and R3 can see R1 docs, R5 can see R4 docs
  const visibilityLinks = [
    { roundId: rounds[1].id, submissionWindowId: submissionWindow1.id }, // R2 sees R1 docs
    { roundId: rounds[2].id, submissionWindowId: submissionWindow1.id }, // R3 sees R1 docs
    { roundId: rounds[4].id, submissionWindowId: submissionWindow1.id }, // R5 sees R1 docs
    { roundId: rounds[4].id, submissionWindowId: submissionWindow2.id }, // R5 sees R4 docs
  ]

  for (const link of visibilityLinks) {
    await prisma.roundSubmissionVisibility.upsert({
      where: {
        roundId_submissionWindowId: {
          roundId: link.roundId,
          submissionWindowId: link.submissionWindowId,
        },
      },
      update: {},
      create: link,
    })
  }
  console.log(`   ✓ ${visibilityLinks.length} submission visibility links created`)

  // --- Applicant/Observer visibility settings ---
  const visibilitySettings = [
    { key: 'observer_show_team_tab', value: 'true', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show Team tab on observer project detail page' },
    { key: 'applicant_show_evaluation_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show anonymous jury evaluation feedback to applicants' },
    { key: 'applicant_show_evaluation_scores', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show global scores in evaluation feedback' },
    { key: 'applicant_show_evaluation_criteria', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show per-criterion scores in evaluation feedback' },
    { key: 'applicant_show_evaluation_text', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show written feedback text in evaluation feedback' },
    { key: 'applicant_show_livefinal_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show live final scores to applicants' },
    { key: 'applicant_show_livefinal_scores', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show individual jury scores from live finals' },
    { key: 'applicant_show_deliberation_feedback', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Show deliberation results to applicants' },
    { key: 'applicant_hide_feedback_from_rejected', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Hide feedback from rejected projects' },
    { key: 'applicant_allow_description_edit', value: 'false', type: SettingType.BOOLEAN, category: SettingCategory.ANALYTICS, description: 'Allow applicants to edit their project description' },
  ]
  for (const s of visibilitySettings) {
    await prisma.systemSettings.upsert({
      where: { key: s.key },
      update: {},
      create: s,
    })
  }
  console.log(`   ✓ Created ${visibilitySettings.length} applicant/observer visibility settings`)

  // --- Feature flag: enable competition model ---
  await prisma.systemSettings.upsert({
    where: { key: 'feature.useCompetitionModel' },
    update: { value: 'true' },
    create: {
      key: 'feature.useCompetitionModel',
      value: 'true',
      type: SettingType.BOOLEAN,
      category: SettingCategory.FEATURE_FLAGS,
      description: 'Use Competition/Round model (legacy Pipeline system removed)',
    },
  })
  console.log('   ✓ Feature flag: feature.useCompetitionModel = true')

  // ==========================================================================
  // 9. Notification Email Settings
  // ==========================================================================
  console.log('\n🔔 Creating notification email settings...')

  const notificationSettings = [
    // Team / Applicant notifications
    { notificationType: 'APPLICATION_SUBMITTED', category: 'team', label: 'Application Submitted', description: 'When a team submits their application', sendEmail: true },
    { notificationType: 'TEAM_INVITE_RECEIVED', category: 'team', label: 'Team Invitation Received', description: 'When someone is invited to join a team', sendEmail: true },
    { notificationType: 'TEAM_MEMBER_JOINED', category: 'team', label: 'Team Member Joined', description: 'When a new member joins the team', sendEmail: false },
    { notificationType: 'ADVANCED_SEMIFINAL', category: 'team', label: 'Advanced to Semi-Finals', description: 'When a project advances to semi-finals', sendEmail: true },
    { notificationType: 'ADVANCED_FINAL', category: 'team', label: 'Selected as Finalist', description: 'When a project is selected as a finalist', sendEmail: true },
    { notificationType: 'MENTOR_ASSIGNED', category: 'team', label: 'Mentor Assigned', description: 'When a mentor is assigned to the team', sendEmail: true },
    { notificationType: 'NOT_SELECTED', category: 'team', label: 'Not Selected', description: 'When a project is not selected for the next round', sendEmail: true },
    { notificationType: 'FEEDBACK_AVAILABLE', category: 'team', label: 'Feedback Available', description: 'When jury feedback becomes available', sendEmail: true },
    { notificationType: 'WINNER_ANNOUNCEMENT', category: 'team', label: 'Winner Announcement', description: 'When a project wins an award', sendEmail: true },
    // Jury notifications
    { notificationType: 'ASSIGNED_TO_PROJECT', category: 'jury', label: 'Assigned to Project', description: 'When a jury member is assigned to a project', sendEmail: true },
    { notificationType: 'BATCH_ASSIGNED', category: 'jury', label: 'Batch Assignment', description: 'When multiple projects are assigned at once', sendEmail: true },
    { notificationType: 'ROUND_NOW_OPEN', category: 'jury', label: 'Round Now Open', description: 'When a round opens for evaluation', sendEmail: true },
    { notificationType: 'REMINDER_24H', category: 'jury', label: 'Reminder (24h)', description: 'Reminder 24 hours before deadline', sendEmail: true },
    { notificationType: 'REMINDER_1H', category: 'jury', label: 'Reminder (1h)', description: 'Urgent reminder 1 hour before deadline', sendEmail: true },
    { notificationType: 'ROUND_CLOSED', category: 'jury', label: 'Round Closed', description: 'When a round closes', sendEmail: false },
    { notificationType: 'AWARD_VOTING_OPEN', category: 'jury', label: 'Award Voting Open', description: 'When special award voting opens', sendEmail: true },
    { notificationType: 'COI_REASSIGNED', category: 'jury', label: 'COI Reassignment', description: 'When a project is reassigned to you due to another juror\'s conflict of interest', sendEmail: true },
    { notificationType: 'MANUAL_REASSIGNED', category: 'jury', label: 'Manual Reassignment', description: 'When an admin manually reassigns a project to you', sendEmail: true },
    // Mentor notifications
    { notificationType: 'MENTEE_ASSIGNED', category: 'mentor', label: 'Mentee Assigned', description: 'When assigned as mentor to a project', sendEmail: true },
    { notificationType: 'MENTEE_UPLOADED_DOCS', category: 'mentor', label: 'Mentee Documents Updated', description: 'When a mentee uploads new documents', sendEmail: false },
    { notificationType: 'MENTEE_ADVANCED', category: 'mentor', label: 'Mentee Advanced', description: 'When a mentee advances to the next round', sendEmail: true },
    { notificationType: 'MENTEE_FINALIST', category: 'mentor', label: 'Mentee is Finalist', description: 'When a mentee is selected as finalist', sendEmail: true },
    { notificationType: 'MENTEE_WON', category: 'mentor', label: 'Mentee Won', description: 'When a mentee wins an award', sendEmail: true },
    // Observer notifications
    { notificationType: 'ROUND_STARTED', category: 'observer', label: 'Round Started', description: 'When a new round begins', sendEmail: false },
    { notificationType: 'ROUND_COMPLETED', category: 'observer', label: 'Round Completed', description: 'When a round is completed', sendEmail: true },
    { notificationType: 'FINALISTS_ANNOUNCED', category: 'observer', label: 'Finalists Announced', description: 'When finalists are announced', sendEmail: true },
    { notificationType: 'WINNERS_ANNOUNCED', category: 'observer', label: 'Winners Announced', description: 'When winners are announced', sendEmail: true },
    // Admin notifications
    { notificationType: 'FILTERING_COMPLETE', category: 'admin', label: 'AI Filtering Complete', description: 'When AI filtering job completes', sendEmail: false },
    { notificationType: 'FILTERING_FAILED', category: 'admin', label: 'AI Filtering Failed', description: 'When AI filtering job fails', sendEmail: true },
    { notificationType: 'NEW_APPLICATION', category: 'admin', label: 'New Application', description: 'When a new application is received', sendEmail: false },
    { notificationType: 'SYSTEM_ERROR', category: 'admin', label: 'System Error', description: 'When a system error occurs', sendEmail: true },
  ]

  for (const setting of notificationSettings) {
    await prisma.notificationEmailSetting.upsert({
      where: { notificationType: setting.notificationType },
      update: {
        category: setting.category,
        label: setting.label,
        description: setting.description,
      },
      create: setting,
    })
  }
  console.log(`   ✓ Created ${notificationSettings.length} notification email settings`)

  // ==========================================================================
  // 10. Summary
  // ==========================================================================
  console.log('\n' + '='.repeat(60))
  console.log('✅ SEEDING COMPLETE')
  console.log('='.repeat(60))
  console.log(`\n  Program:       ${program.name} ${program.year}\n\n  Competition:    ${competition.name} (${competition.slug})\n  Rounds:         ${rounds.length} (R1-R8)\n  Jury Groups:    3 (Screening, Expert, Finals)\n  Sub. Windows:   2 (R1 Application, R4 Semi-finalist)\n\n  Projects:    ${projectCount} (from CSV)\n  Users:       ${3 + juryMembers.length + mentors.length + observers.length + projectCount} total\n    - Admin/Staff: 3\n    - Jury:        ${juryMembers.length}\n    - Mentors:     ${mentors.length}\n    - Observers:   ${observers.length}\n    - Applicants:  ${projectCount}\n\n  Login:  matt@monaco-opc.com / 195260Mp!\n  `)
}

main()
  .catch((e) => {
    console.error('❌ Seeding failed:', e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
