import { describe, expect, test } from 'vitest';

import {
  buildAttachmentUploadMetadata,
  buildAttachmentUploadFormData,
  createUploadedAttachmentFromServer,
  getTextAttachmentType,
  isOfficeXml,
  normalizeAttachmentMimeType,
  toAttachmentUploadDescriptor
} from './attachment-upload.js';

describe('toAttachmentUploadDescriptor', () => {
  test('preserves explicit names for non-File uploads', () => {
    const descriptor = toAttachmentUploadDescriptor({
      data: 'data:image/webp;base64,Zm9v',
      mimeType: 'image/webp',
      name: 'capture.webp'
    });

    expect(descriptor).toMatchObject({
      fileName: 'capture.webp',
      mimeType: 'image/webp'
    });
  });

  test('falls back to mime-derived filenames for unnamed non-File uploads', () => {
    const descriptor = toAttachmentUploadDescriptor({
      data: 'data:application/pdf;base64,Zm9v',
      mimeType: 'application/pdf'
    });

    expect(descriptor).toMatchObject({
      fileName: 'attachment.pdf',
      mimeType: 'application/pdf'
    });
  });

  test('normalizes browser ts mime types from filename when they are not text-like', () => {
    const descriptor = toAttachmentUploadDescriptor(new File(['const answer = 42;'], 'main.ts', { type: 'video/mp2t' }));

    expect(descriptor).toMatchObject({
      fileName: 'main.ts',
      mimeType: 'text/plain'
    });
    expect(descriptor?.blob.type).toBe('text/plain');
  });

  test('normalizes blank browser mime types for python files', () => {
    const descriptor = toAttachmentUploadDescriptor(new File(['print("hi")'], 'script.py', { type: '' }));

    expect(descriptor).toMatchObject({
      fileName: 'script.py',
      mimeType: 'text/plain'
    });
    expect(descriptor?.blob.type).toBe('text/plain');
  });
});

describe('buildAttachmentUploadFormData', () => {
  test('appends the normalized filename to form data', () => {
    const descriptor = toAttachmentUploadDescriptor({
      data: 'data:image/webp;base64,Zm9v',
      mimeType: 'image/webp',
      name: 'capture.webp'
    });

    expect(descriptor).not.toBeNull();

    const formData = buildAttachmentUploadFormData({
      descriptor: descriptor!,
      prefix: 'captured-screenshot'
    });

    const uploadedFile = formData.get('file');
    expect(uploadedFile).toBeInstanceOf(File);
    expect((uploadedFile as File).name).toBe('capture.webp');
    expect(formData.get('prefix')).toBe('captured-screenshot');
  });

  test('appends serialized metadata when provided', () => {
    const descriptor = toAttachmentUploadDescriptor({
      data: 'data:text/plain;base64,Zm9v',
      mimeType: 'text/plain',
      name: 'notes.txt'
    });

    expect(descriptor).not.toBeNull();

    const formData = buildAttachmentUploadFormData({
      descriptor: descriptor!,
      prefix: 'message-attachment',
      metadata: buildAttachmentUploadMetadata({
        label: 'Error screenshot',
        insight: 'Shows a missing submit button'
      })
    });

    expect(formData.get('metadata')).toBe(
      JSON.stringify({
        label: 'Error screenshot',
        insight: 'Shows a missing submit button'
      })
    );
  });
});

describe('createUploadedAttachmentFromServer', () => {
  test('falls back to the original mime type when the server omits one', () => {
    const uploadedAttachment = createUploadedAttachmentFromServer({
      response: {
        attachmentId: '123',
        fileName: '',
        contentUrl: '/api/v1/files/content/123',
        mimeType: null,
        purpose: 'attachment',
        scopeType: 'app',
        signedUrl: 'https://signed.example/123',
        signedUrlExpiresAt: '2026-03-06T00:00:00.000Z',
        storageKey: 'message-attachment/123'
      },
      fallbackFileName: 'spec.pdf',
      fallbackMimeType: 'application/pdf',
      label: 'Spec',
      insight: 'Reference doc'
    });

    expect(uploadedAttachment).toEqual({
      type: 'uploaded',
      url: '/api/v1/files/content/123',
      signedUrl: 'https://signed.example/123',
      mediaType: 'application/pdf',
      fileName: 'spec.pdf',
      label: 'Spec',
      insight: 'Reference doc',
      storageKey: 'message-attachment/123',
      signedUrlExpiresAt: '2026-03-06T00:00:00.000Z',
      scopeType: 'app',
      applicationId: undefined
    });
  });
});

describe('buildAttachmentUploadMetadata', () => {
  test('normalizes non-empty label and insight fields', () => {
    expect(
      buildAttachmentUploadMetadata({
        label: 'Error screenshot',
        insight: 'Shows a missing submit button'
      })
    ).toEqual({
      label: 'Error screenshot',
      insight: 'Shows a missing submit button'
    });
  });
});

describe('normalizeAttachmentMimeType', () => {
  test('prefers text-safe mime types for text-like filenames', () => {
    expect(
      normalizeAttachmentMimeType({
        fileName: 'component.tsx',
        mimeType: 'video/mp2t'
      })
    ).toBe('text/plain');
  });
});

describe('getTextAttachmentType', () => {
  test('returns null for office/openxml files even when mime is text-like', () => {
    expect(
      getTextAttachmentType({
        fileName: 'proposal.docx',
        mimeType: 'text/plain'
      })
    ).toBeNull();
  });

  test('still classifies markdown as text', () => {
    expect(
      getTextAttachmentType({
        fileName: 'readme.md',
        mimeType: 'text/markdown'
      })
    ).toBe('txt');
  });
});

describe('isOfficeXml', () => {
  test('returns true for office file extensions even with text mime type', () => {
    expect(
      isOfficeXml({
        fileName: 'requirements.docx',
        mimeType: 'text/plain'
      })
    ).toBe(true);
  });

  test('returns true for office mime types without filename', () => {
    expect(
      isOfficeXml({
        mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
      })
    ).toBe(true);
  });

  test('returns false for markdown files', () => {
    expect(
      isOfficeXml({
        fileName: 'readme.md',
        mimeType: 'text/markdown'
      })
    ).toBe(false);
  });
});
