import { describe, expect, it } from "vitest"

import {
  SendMessageSchema,
  MessageIdSchema,
  UpdateNotificationPreferencesSchema,
} from "./schema"

describe("SendMessageSchema", () => {
  it("should parse valid input with all fields", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: "Hello",
      content: "World",
      parentMessageId: "msg-1",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.receiverId).toBe("user-1")
      expect(result.data.subject).toBe("Hello")
      expect(result.data.content).toBe("World")
      expect(result.data.parentMessageId).toBe("msg-1")
    }
  })

  it("should parse valid input with only required fields", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "Hello",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.receiverId).toBe("user-1")
      expect(result.data.content).toBe("Hello")
      expect(result.data.subject).toBeNull()
      expect(result.data.parentMessageId).toBeNull()
    }
  })

  it("should transform empty subject string to null", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: "",
      content: "Hello",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.subject).toBeNull()
    }
  })

  it("should transform empty parentMessageId string to null", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "Hello",
      parentMessageId: "",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.parentMessageId).toBeNull()
    }
  })

  it("should accept nullable subject", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: null,
      content: "Hello",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.subject).toBeNull()
    }
  })

  it("should accept nullable parentMessageId", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "Hello",
      parentMessageId: null,
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.parentMessageId).toBeNull()
    }
  })

  it("should reject empty receiverId", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "",
      content: "Hello",
    })

    expect(result.success).toBe(false)
  })

  it("should reject whitespace-only receiverId after trim", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "   ",
      content: "Hello",
    })

    expect(result.success).toBe(false)
  })

  it("should reject empty content", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "",
    })

    expect(result.success).toBe(false)
  })

  it("should reject whitespace-only content after trim", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "   ",
    })

    expect(result.success).toBe(false)
  })

  it("should reject missing receiverId", () => {
    const result = SendMessageSchema.safeParse({
      content: "Hello",
    })

    expect(result.success).toBe(false)
  })

  it("should reject missing content", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
    })

    expect(result.success).toBe(false)
  })

  it("should reject subject exceeding 255 chars", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: "a".repeat(256),
      content: "Hello",
    })

    expect(result.success).toBe(false)
  })

  it("should accept subject of exactly 255 chars", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: "a".repeat(255),
      content: "Hello",
    })

    expect(result.success).toBe(true)
  })

  it("should trim whitespace from receiverId", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "  user-1  ",
      content: "Hello",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.receiverId).toBe("user-1")
    }
  })

  it("should trim whitespace from content", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      content: "  Hello  ",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.content).toBe("Hello")
    }
  })

  it("should trim whitespace from subject", () => {
    const result = SendMessageSchema.safeParse({
      receiverId: "user-1",
      subject: "  Hello  ",
      content: "Hello",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.subject).toBe("Hello")
    }
  })
})

describe("MessageIdSchema", () => {
  it("should parse valid messageId", () => {
    const result = MessageIdSchema.safeParse({ messageId: "msg-1" })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.messageId).toBe("msg-1")
    }
  })

  it("should reject empty messageId", () => {
    const result = MessageIdSchema.safeParse({ messageId: "" })

    expect(result.success).toBe(false)
  })

  it("should reject whitespace-only messageId after trim", () => {
    const result = MessageIdSchema.safeParse({ messageId: "   " })

    expect(result.success).toBe(false)
  })

  it("should reject missing messageId", () => {
    const result = MessageIdSchema.safeParse({})

    expect(result.success).toBe(false)
  })

  it("should trim whitespace from messageId", () => {
    const result = MessageIdSchema.safeParse({ messageId: "  msg-1  " })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.messageId).toBe("msg-1")
    }
  })
})

describe("UpdateNotificationPreferencesSchema", () => {
  const validInput = {
    emailEnabled: true,
    smsEnabled: false,
    pushEnabled: true,
    homeworkNotifications: true,
    gradeNotifications: true,
    announcementNotifications: true,
    messageNotifications: true,
    attendanceNotifications: false,
    quietHoursEnabled: false,
  }

  it("should parse valid input without quiet hours times", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse(validInput)

    expect(result.success).toBe(true)
  })

  it("should parse valid input with quiet hours times", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursStart: "22:00",
      quietHoursEnd: "07:00",
    })

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.quietHoursStart).toBe("22:00")
      expect(result.data.quietHoursEnd).toBe("07:00")
    }
  })

  it("should accept null quiet hours times", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursStart: null,
      quietHoursEnd: null,
    })

    expect(result.success).toBe(true)
  })

  it("should accept undefined quiet hours times", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse(validInput)

    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data.quietHoursStart).toBeUndefined()
      expect(result.data.quietHoursEnd).toBeUndefined()
    }
  })

  it("should reject invalid time format for quietHoursStart", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursStart: "25:00",
    })

    expect(result.success).toBe(false)
  })

  it("should reject invalid time format for quietHoursEnd", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursEnd: "12:60",
    })

    expect(result.success).toBe(false)
  })

  it("should reject non-time string for quietHoursStart", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursStart: "not-a-time",
    })

    expect(result.success).toBe(false)
  })

  it("should accept boundary time 00:00", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursStart: "00:00",
    })

    expect(result.success).toBe(true)
  })

  it("should accept boundary time 23:59", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      quietHoursEnd: "23:59",
    })

    expect(result.success).toBe(true)
  })

  it("should reject non-boolean emailEnabled", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      emailEnabled: "yes",
    })

    expect(result.success).toBe(false)
  })

  it("should reject non-boolean smsEnabled", () => {
    const result = UpdateNotificationPreferencesSchema.safeParse({
      ...validInput,
      smsEnabled: 1,
    })

    expect(result.success).toBe(false)
  })

  it("should reject missing required boolean field", () => {
    const inputWithoutEmail = {
      smsEnabled: false,
      pushEnabled: true,
      homeworkNotifications: true,
      gradeNotifications: true,
      announcementNotifications: true,
      messageNotifications: true,
      attendanceNotifications: false,
      quietHoursEnabled: false,
    }
    const result = UpdateNotificationPreferencesSchema.safeParse(inputWithoutEmail)

    expect(result.success).toBe(false)
  })
})
