import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import express from 'express';
import request from 'supertest';
import initSqlJs from 'sql.js';
import { readFileSync } from 'fs';
import { createImportLocalRoutes } from '../routes/importLocal.js';
import { getDatabase, saveDatabase } from '../db/database.js';
import path from 'path';

describe('Import Local Files (CopyMeThat upload)', () => {
  let app: express.Application;
  let db: any;

  const setupDB = async () => {
    const SQL = await initSqlJs();
    db = new SQL.Database();
    const schemaPath = new URL('../db/schema.sql', import.meta.url).pathname;
    const schema = readFileSync(schemaPath, 'utf-8');
    db.exec(schema);
    await getDatabase('data/test-upload.db'); // initialize singleton
    // We'll rely on createImportLocalRoutes using getDatabaseSync()
  };

  beforeEach(async () => {
    await setupDB();
    app = express();
    app.use(express.json());
    // Use multipart for file upload
    // The route uses multer internally; no extra middleware needed
    app.use('/api/import/local', createImportLocalRoutes());
  });

  afterEach(() => {
    // Clean up uploaded files artifacts if any
  });

  it('imports valid HTML file', async () => {
    const html = `
      <div class="recipe">
        <div id="name">Uploaded Recipe</div>
        <ul><li class="recipeIngredient">ingredient 1</li></ul>
        <ul><li class="instruction">step 1</li></ul>
      </div>
    `;
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', Buffer.from(html), 'recipe.html')
      .field('skipDuplicates', 'true')
      .field('importImages', 'false')
      .expect(200);

    expect(response.body.success).toBe(true);
    expect(response.body.data.imported).toBe(1);
    expect(response.body.data.skipped).toBe(0);
    expect(response.body.data.failed).toBe(0);
    expect(response.body.data.recipes).toHaveLength(1);
    expect(response.body.data.recipes[0].title).toBe('Uploaded Recipe');
  });

  it('imports valid TXT file', async () => {
    const txt = `TXT Recipe

INGREDIENTS
a
b

STEPS
x
y
`;
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', Buffer.from(txt), 'recipe.txt')
      .expect(200);

    expect(response.body.success).toBe(true);
    expect(response.body.data.imported).toBe(1);
    expect(response.body.data.recipes[0].title).toBe('TXT Recipe');
  });

  it('imports multiple mixed files', async () => {
    const html = `<div class="recipe"><div id="name">H</div><ul><li class="recipeIngredient">i</li></ul><ul><li class="instruction">s</li></ul></div>`;
    const txt = `T\n\nINGREDIENTS\na\nSTEPS\nb`;
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', Buffer.from(html), 'a.html')
      .attach('files', Buffer.from(txt), 'b.txt')
      .expect(200);

    expect(response.body.data.imported).toBe(2);
    const titles = response.body.data.recipes.map((r: any) => r.title);
    expect(titles).toContain('H');
    expect(titles).toContain('T');
  });

  it('rejects non-.html/.txt files', async () => {
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', Buffer.from('content'), 'file.pdf')
      .expect(400);

    expect(response.body.success).toBe(false);
    expect(String(response.body.error)).toMatch(/Invalid file type/);
  });

  it('rejects no files', async () => {
    const response = await request(app)
      .post('/api/import/local')
      .expect(400);

    expect(response.body.success).toBe(false);
    expect(String(response.body.error)).toMatch(/No files uploaded/);
  });

  it('handles parse failures gracefully', async () => {
    const badHtml = `<div class="recipe"><div id="name">Bad</div><ul></ul><ul></ul></div>`;
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', Buffer.from(badHtml), 'bad.html')
      .expect(200); // still 200, but failed count increments

    expect(response.body.success).toBe(false);
    expect(response.body.data.failed).toBe(1);
    expect(response.body.data.imported).toBe(0);
  });

  it('enforces file size limit (rejects oversized)', async () => {
    // 60MB payload exceeds 50MB limit
    const bigContent = Buffer.alloc(60 * 1024 * 1024, 'a');
    const response = await request(app)
      .post('/api/import/local')
      .attach('files', bigContent, 'big.html')
      .expect(413); // Payload Too Large

    expect(response.body.success).toBe(false);
    expect(String(response.body.error)).toMatch(/too large|limit/i);
  });

  it('max files limit (200) not exceeded in test', () => {
    // We won't test 200 files here; just verify normal upload works
    // This is a placeholder for a more thorough load test
  });
});
