'use server'

import { and, asc, count, eq, isNull } from 'drizzle-orm'
// import { PROJECTS_CACHE_TAG } from '@/api/projects/service'
import { getUserBillingStatus } from '@/cache/billing'
import { formatLocalDateOnly } from '@/lib/custom-fields'
import { authedActionClient } from '@/lib/safe-action'
import { titleToSlug } from '@/lib/utils'
import { FREE_PLAN_LIMITS } from '@/limits'
import { db } from '@/server/db'
import {
  customFields,
  members,
  projects,
  requirements,
  settings as settingsTable,
} from '@/server/db/schema'
import { createProjectSchema } from './common'

export const createProjectAction = authedActionClient
  .inputSchema(createProjectSchema)
  .action(
    async ({
      parsedInput: {
        organizationId,
        name,
        description,
        dueDate,
        invoiceFromName,
        invoiceFromAddress,
        invoiceToName,
        invoiceToAddress,
      },
      ctx: { orgMember, role },
    }) => {
      if (!role.authorize({ project: ['create'] }).success) {
        throw new Error('You do not have permission to create projects')
      }

      if (orgMember.organizationId !== organizationId) {
        throw new Error('Workspace mismatch')
      }

      const { slugified, slugifiedWithSuffix } = titleToSlug(name)

      const project = await db.transaction(async (tx) => {
        const [ownerRow] = await tx
          .select({ ownerId: members.userId })
          .from(members)
          .where(
            and(
              eq(members.organizationId, organizationId),
              eq(members.role, 'owner')
            )
          )
          .for('update')
          .limit(1)

        if (!ownerRow) {
          throw new Error('Workspace owner not found')
        }

        const ownerHasPro = await getUserBillingStatus(ownerRow.ownerId)
        if (!ownerHasPro) {
          const [projectCountRow] = await tx
            .select({ value: count() })
            .from(projects)
            .innerJoin(
              members,
              eq(members.organizationId, projects.organizationId)
            )
            .where(
              and(
                eq(members.userId, ownerRow.ownerId),
                eq(members.role, 'owner')
              )
            )
          const projectCount = projectCountRow?.value ?? 0
          if (projectCount >= FREE_PLAN_LIMITS.PROJECTS) {
            throw new Error(
              `Free plan is limited to ${FREE_PLAN_LIMITS.PROJECTS} projects across all workspaces. Please upgrade to Pro.`
            )
          }
        }

        const [projectWithSlug] = await tx
          .select({ id: projects.id })
          .from(projects)
          .where(
            and(
              eq(projects.organizationId, organizationId),
              eq(projects.slug, slugified)
            )
          )
          .limit(1)

        const [createdProject] = await tx
          .insert(projects)
          .values({
            name,
            slug: projectWithSlug ? slugifiedWithSuffix : slugified,
            description: description || null,
            organizationId,
            dueDate: dueDate ? formatLocalDateOnly(dueDate) : null,
          })
          .returning()

        if (!createdProject) {
          throw new Error('Failed to create project')
        }

        // This is the requirement called "General Work"
        await tx.insert(requirements).values({
          projectId: createdProject.id,
          slug: 'saturn_default_general_work',
          title: 'General Work',
          body: '<h1> This is a default requirement generated by Saturn to categorize under General Work <h1>',
          status: 'client_accepted',
          authorId: orgMember.id,
        })

        const orgTemplates = await tx
          .select({
            label: customFields.label,
            type: customFields.type,
            required: customFields.required,
            visibleToClient: customFields.visibleToClient,
            defaultValue: customFields.defaultValue,
            options: customFields.options,
            config: customFields.config,
          })
          .from(customFields)
          .where(
            and(
              eq(customFields.organizationId, organizationId),
              isNull(customFields.projectId)
            )
          )
          .orderBy(asc(customFields.createdAt))

        if (orgTemplates.length > 0) {
          await tx.insert(customFields).values(
            orgTemplates.map((t) => ({
              ...t,
              organizationId,
              projectId: createdProject.id,
            }))
          )
        }

        const fromName = invoiceFromName?.trim() || null
        const fromAddress = invoiceFromAddress?.trim() || null
        const toName = invoiceToName?.trim() || null
        const toAddress = invoiceToAddress?.trim() || null
        if (fromName || fromAddress || toName || toAddress) {
          await tx.insert(settingsTable).values({
            organizationId,
            projectId: createdProject.id,
            invoiceFromName: fromName,
            invoiceFromAddress: fromAddress,
            invoiceToName: toName,
            invoiceToAddress: toAddress,
          })
        }

        return createdProject
      })

      // revalidateTag(PROJECTS_CACHE_TAG,"max")
      return project
    }
  )
