import {
  createMembership,
  createOrganization,
  MembershipRepository,
  OrganizationRepository,
} from "@domain/organizations"
import { createFakeMembershipRepository, createFakeOrganizationRepository } from "@domain/organizations/testing"
import { OrganizationId, SqlClient, UserId } from "@domain/shared"
import { createFakeSqlClient } from "@domain/shared/testing"
import { Effect, Layer } from "effect"
import { describe, expect, it } from "vitest"
import type { User } from "../entities/user.ts"
import { UserRepository } from "../ports/user-repository.ts"
import { createFakeUserRepository } from "../testing/fake-user-repository.ts"
import { deleteUserUseCase } from "./delete-user.ts"

/** CUID-shaped ids — entity factories validate via Zod (`@domain/shared` seeds). */
const USER_ID = "ye9d77pxi50nh1gyqljkffnb"
const ORG_ID = OrganizationId("iapkf6osmlm7mbw9kulosua4")

const createTestUser = (id: string): User => ({
  id: UserId(id),
  email: `${id}@example.com`,
  name: "Test User",
  jobTitle: null,
  phoneNumber: null,
  emailVerified: true,
  image: null,
  role: "user",
  notificationPreferences: null,
  createdAt: new Date(),
})

const createTestLayers = () => {
  const { repository: userRepo, users } = createFakeUserRepository()
  const { repository: orgRepo, organizations } = createFakeOrganizationRepository()
  const { repository: membershipRepo, memberships } = createFakeMembershipRepository()
  const fakeSqlClient = createFakeSqlClient()

  const testLayers = Layer.mergeAll(
    Layer.succeed(UserRepository, userRepo),
    Layer.succeed(OrganizationRepository, orgRepo),
    Layer.succeed(MembershipRepository, membershipRepo),
    Layer.succeed(SqlClient, fakeSqlClient),
  )

  return { users, organizations, memberships, testLayers }
}

describe("deleteUserUseCase", () => {
  it("deletes the user record", async () => {
    const { users, testLayers } = createTestLayers()
    users.set(USER_ID, createTestUser(USER_ID))

    await Effect.runPromise(deleteUserUseCase({ userId: USER_ID }).pipe(Effect.provide(testLayers)))

    expect(users.has(USER_ID)).toBe(false)
  })

  it("cleans up memberships and sole-member orgs before deleting user", async () => {
    const { users, organizations, memberships, testLayers } = createTestLayers()
    users.set(USER_ID, createTestUser(USER_ID))

    const org = createOrganization({ id: ORG_ID, name: "Solo Org", slug: "solo-org" })
    organizations.set(ORG_ID, org)

    const m = createMembership({ organizationId: ORG_ID, userId: UserId(USER_ID), role: "owner" })
    memberships.set(m.id, m)

    await Effect.runPromise(deleteUserUseCase({ userId: USER_ID }).pipe(Effect.provide(testLayers)))

    expect(users.has(USER_ID)).toBe(false)
    expect(organizations.has(ORG_ID)).toBe(false)
  })

  it("works when user has no memberships", async () => {
    const { users, testLayers } = createTestLayers()
    users.set(USER_ID, createTestUser(USER_ID))

    await Effect.runPromise(deleteUserUseCase({ userId: USER_ID }).pipe(Effect.provide(testLayers)))

    expect(users.has(USER_ID)).toBe(false)
  })
})
