/**
 * @vitest-environment node
 */
import {
  authMockFns,
  hybridAuthMockFns,
  storageServiceMock,
  storageServiceMockFns,
} from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'

const mocks = vi.hoisted(() => {
  const mockVerifyFileAccess = vi.fn()
  const mockVerifyWorkspaceFileAccess = vi.fn()
  const mockGetStorageProvider = vi.fn()
  const mockIsUsingCloudStorage = vi.fn()

  return {
    mockVerifyFileAccess,
    mockVerifyWorkspaceFileAccess,
    mockGetStorageProvider,
    mockIsUsingCloudStorage,
  }
})

vi.mock('drizzle-orm', () => ({
  and: vi.fn((...conditions: unknown[]) => ({ conditions, type: 'and' })),
  eq: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'eq' })),
  or: vi.fn((...conditions: unknown[]) => ({ type: 'or', conditions })),
  gte: vi.fn((field: unknown, value: unknown) => ({ type: 'gte', field, value })),
  lte: vi.fn((field: unknown, value: unknown) => ({ type: 'lte', field, value })),
  gt: vi.fn((field: unknown, value: unknown) => ({ type: 'gt', field, value })),
  lt: vi.fn((field: unknown, value: unknown) => ({ type: 'lt', field, value })),
  ne: vi.fn((field: unknown, value: unknown) => ({ type: 'ne', field, value })),
  asc: vi.fn((field: unknown) => ({ field, type: 'asc' })),
  desc: vi.fn((field: unknown) => ({ field, type: 'desc' })),
  isNull: vi.fn((field: unknown) => ({ field, type: 'isNull' })),
  isNotNull: vi.fn((field: unknown) => ({ field, type: 'isNotNull' })),
  inArray: vi.fn((field: unknown, values: unknown) => ({ field, values, type: 'inArray' })),
  notInArray: vi.fn((field: unknown, values: unknown) => ({ field, values, type: 'notInArray' })),
  like: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'like' })),
  ilike: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'ilike' })),
  count: vi.fn((field: unknown) => ({ field, type: 'count' })),
  sum: vi.fn((field: unknown) => ({ field, type: 'sum' })),
  avg: vi.fn((field: unknown) => ({ field, type: 'avg' })),
  min: vi.fn((field: unknown) => ({ field, type: 'min' })),
  max: vi.fn((field: unknown) => ({ field, type: 'max' })),
  sql: vi.fn((strings: unknown, ...values: unknown[]) => ({ type: 'sql', sql: strings, values })),
}))

vi.mock('@sim/utils/id', () => ({
  generateId: vi.fn(() => 'test-uuid'),
  generateShortId: vi.fn(() => 'mock-short-id'),
  isValidUuid: vi.fn((v: string) =>
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v)
  ),
}))

vi.mock('@/app/api/files/authorization', () => ({
  verifyFileAccess: mocks.mockVerifyFileAccess,
  verifyWorkspaceFileAccess: mocks.mockVerifyWorkspaceFileAccess,
}))

vi.mock('@/lib/uploads', () => ({
  getStorageProvider: mocks.mockGetStorageProvider,
  isUsingCloudStorage: mocks.mockIsUsingCloudStorage,
  StorageService: {
    uploadFile: storageServiceMockFns.mockUploadFile,
    downloadFile: storageServiceMockFns.mockDownloadFile,
    deleteFile: storageServiceMockFns.mockDeleteFile,
    hasCloudStorage: storageServiceMockFns.mockHasCloudStorage,
  },
  uploadFile: storageServiceMockFns.mockUploadFile,
  downloadFile: storageServiceMockFns.mockDownloadFile,
  deleteFile: storageServiceMockFns.mockDeleteFile,
  hasCloudStorage: storageServiceMockFns.mockHasCloudStorage,
}))

vi.mock('@/lib/uploads/core/storage-service', () => storageServiceMock)

vi.mock('@/lib/uploads/server/metadata', () => ({
  deleteFileMetadata: vi.fn().mockResolvedValue(undefined),
}))

vi.mock('@/lib/uploads/setup.server', () => ({}))

vi.mock('fs/promises', () => ({
  unlink: vi.fn().mockResolvedValue(undefined),
  access: vi.fn().mockResolvedValue(undefined),
  stat: vi.fn().mockResolvedValue({ isFile: () => true }),
}))

import { createMockRequest } from '@sim/testing'
import { POST } from '@/app/api/files/delete/route'

describe('File Delete API Route', () => {
  beforeEach(() => {
    vi.clearAllMocks()

    vi.stubGlobal('crypto', {
      randomUUID: vi.fn().mockReturnValue('mock-uuid-1234-5678'),
    })

    authMockFns.mockGetSession.mockResolvedValue({ user: { id: 'test-user-id' } })
    hybridAuthMockFns.mockCheckSessionOrInternalAuth.mockResolvedValue({
      success: true,
      userId: 'test-user-id',
      error: undefined,
    })
    mocks.mockVerifyFileAccess.mockResolvedValue(true)
    mocks.mockVerifyWorkspaceFileAccess.mockResolvedValue(true)
    storageServiceMockFns.mockDeleteFile.mockResolvedValue(undefined)
    storageServiceMockFns.mockHasCloudStorage.mockReturnValue(true)
    mocks.mockGetStorageProvider.mockReturnValue('s3')
    mocks.mockIsUsingCloudStorage.mockReturnValue(true)
  })

  it('should handle local file deletion successfully', async () => {
    storageServiceMockFns.mockHasCloudStorage.mockReturnValue(false)
    mocks.mockGetStorageProvider.mockReturnValue('local')
    mocks.mockIsUsingCloudStorage.mockReturnValue(false)

    const req = createMockRequest('POST', {
      filePath: '/api/files/serve/workspace/test-workspace-id/test-file.txt',
    })

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toHaveProperty('success', true)
    expect(data).toHaveProperty('message')
    expect(['File deleted successfully', "File not found, but that's okay"]).toContain(data.message)
  })

  it('should handle file not found gracefully', async () => {
    storageServiceMockFns.mockHasCloudStorage.mockReturnValue(false)
    mocks.mockGetStorageProvider.mockReturnValue('local')
    mocks.mockIsUsingCloudStorage.mockReturnValue(false)

    const req = createMockRequest('POST', {
      filePath: '/api/files/serve/workspace/test-workspace-id/nonexistent.txt',
    })

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toHaveProperty('success', true)
    expect(data).toHaveProperty('message')
  })

  it('should handle S3 file deletion successfully', async () => {
    const req = createMockRequest('POST', {
      filePath: '/api/files/serve/workspace/test-workspace-id/1234567890-test-file.txt',
    })

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toHaveProperty('success', true)
    expect(data).toHaveProperty('message', 'File deleted successfully')

    expect(storageServiceMockFns.mockDeleteFile).toHaveBeenCalledWith({
      key: 'workspace/test-workspace-id/1234567890-test-file.txt',
      context: 'workspace',
    })
  })

  it('should handle Azure Blob file deletion successfully', async () => {
    mocks.mockGetStorageProvider.mockReturnValue('blob')

    const req = createMockRequest('POST', {
      filePath: '/api/files/serve/workspace/test-workspace-id/1234567890-test-document.pdf',
    })

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toHaveProperty('success', true)
    expect(data).toHaveProperty('message', 'File deleted successfully')

    expect(storageServiceMockFns.mockDeleteFile).toHaveBeenCalledWith({
      key: 'workspace/test-workspace-id/1234567890-test-document.pdf',
      context: 'workspace',
    })
  })

  it('should handle missing file path', async () => {
    const req = createMockRequest('POST', {})

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(400)
    expect(data).toHaveProperty('error', 'InvalidRequestError')
    expect(data).toHaveProperty('message', 'No file path provided')
  })

  it('rejects a client context that disagrees with the key prefix', async () => {
    const req = createMockRequest('POST', {
      filePath: '/api/files/serve/s3/workspace/victim-ws/1234-report.pdf',
      context: 'og-images',
    })

    const response = await POST(req)
    const data = await response.json()

    expect(response.status).toBe(400)
    expect(data).toHaveProperty('error', 'InvalidRequestError')
    expect(mocks.mockVerifyFileAccess).not.toHaveBeenCalled()
    expect(storageServiceMockFns.mockDeleteFile).not.toHaveBeenCalled()
  })
})
