import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { selectSections } from '../src/renderer/select-sections';
import { mapToComponents } from '../src/renderer/map-to-components';
import { validateBrief } from '../src/renderer/validate-brief';
import type { Brief, SiteType } from '../src/renderer/types';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const examplePath = resolve(__dirname, '../examples/brief-local-business.json');
const example: Brief = JSON.parse(readFileSync(examplePath, 'utf-8'));

function clone<T>(o: T): T {
  return JSON.parse(JSON.stringify(o));
}

describe('selectSections', () => {
  it('returns sections present in brief', () => {
    const result = selectSections(example);
    expect(result).toContain('hero');
    expect(result).toContain('services');
    expect(result).toContain('contact');
    expect(result).toContain('footer');
  });

  it('preserves order from brief', () => {
    const result = selectSections(example);
    expect(result[0]).toBe('hero');
  });

  it('filters unknown section ids', () => {
    const brief = clone(example);
    (brief.structure as any).sections = ['hero', 'unknown', 'contact'];
    const result = selectSections(brief);
    expect(result).toEqual(['hero', 'contact']);
  });
});

describe('mapToComponents — hero', () => {
  it('builds hero from brief when section present', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.hero).toBeDefined();
    expect(data.hero?.headline).toBe('Trattoria Bella Napoli');
    expect(data.hero?.subheadline).toBe('Traditional Neapolitan cuisine in the heart of Milan.');
  });

  it('does not build hero when section absent', () => {
    const brief = clone(example);
    (brief.structure as any).sections = ['contact', 'footer'];
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    expect(data.hero).toBeUndefined();
  });

  it('resolves phone CTA correctly', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.hero?.primaryCta.href).toBe('tel:+39 02 1234567');
  });

  it('resolves whatsapp CTA with digits only', () => {
    const brief = clone(example);
    (brief.structure as any).primary_cta = 'whatsapp';
    (brief.contacts as any) = {
      whatsapp: '+39 333 123 4567',
      address: 'Via Roma 42',
      city: 'Milano',
    };
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    expect(data.hero?.primaryCta.href).toBe('https://wa.me/393331234567');
  });

  it('resolves form CTA to anchor', () => {
    const brief = clone(example);
    (brief.structure as any).primary_cta = 'form';
    (brief as any).functional = { modules: ['form_capture'] };
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    expect(data.hero?.primaryCta.href).toBe('#contact');
  });
});

describe('mapToComponents — services', () => {
  it('builds services from brief', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.services).toBeDefined();
    expect(data.services?.items).toHaveLength(2);
    expect(data.services?.items[0].title).toBe('Cena tradizionale');
  });

  it('returns undefined when services section absent', () => {
    const brief = clone(example);
    (brief.structure as any).sections = ['hero', 'contact', 'footer'];
    delete (brief as any).services;
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    expect(data.services).toBeUndefined();
  });
});

describe('mapToComponents — contact', () => {
  it('builds contact items in order phone, email, address', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.contact).toBeDefined();
    const types = data.contact?.items.map((i) => i.type);
    expect(types).toEqual(['phone', 'email', 'address']);
  });

  it('builds tel: href for phone', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    const phone = data.contact?.items.find((i) => i.type === 'phone');
    expect(phone?.href).toBe('tel:+39 02 1234567');
  });

  it('builds mailto: href for email', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    const email = data.contact?.items.find((i) => i.type === 'email');
    expect(email?.href).toBe('mailto:info@bellanapoli.example');
  });

  it('builds address from address+city+region', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    const address = data.contact?.items.find((i) => i.type === 'address');
    expect(address?.value).toBe('Via Roma 42, Milano, Lombardia');
  });

  it('omits missing contact channels', () => {
    const brief = clone(example);
    (brief.contacts as any) = {
      email: 'hello@example.com',
      address: 'Via Roma 42',
      city: 'Milano',
    };
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    const types = data.contact?.items.map((i) => i.type);
    expect(types).toEqual(['email', 'address']);
  });
});

describe('mapToComponents — hours', () => {
  it('builds hours when section present', () => {
    const brief = clone(example);
    (brief.structure as any).sections = ['hero', 'hours', 'contact', 'footer'];
    const sections = selectSections(brief);
    const data = mapToComponents(brief, sections);
    expect(data.hours).toBeDefined();
    expect(data.hours?.schedule).toHaveLength(7);
  });

  it('returns undefined when hours section absent', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.hours).toBeUndefined();
  });
});

describe('mapToComponents — footer', () => {
  it('always builds footer', () => {
    const sections = selectSections(example);
    const data = mapToComponents(example, sections);
    expect(data.footer).toBeDefined();
    expect(data.footer.businessName).toBe('Trattoria Bella Napoli');
    expect(data.footer.year).toBeGreaterThan(2020);
  });
});

describe('validateBrief', () => {
  it('accepts valid example', () => {
    expect(() => validateBrief(example)).not.toThrow();
  });

  it('throws on invalid brief', () => {
    const invalid = clone(example);
    delete (invalid.common as any).business_name;
    expect(() => validateBrief(invalid)).toThrow();
  });

  it('accepts all three site types', () => {
    const siteTypes: SiteType[] = ['local_business', 'personal_brand', 'agency'];
    for (const st of siteTypes) {
      const brief = clone(example);
      (brief as any).site_type = st;
      if (st !== 'local_business') {
        delete (brief.contacts as any).address;
        delete (brief.contacts as any).city;
      }
      if (st === 'personal_brand') {
        delete (brief as any).services;
        delete (brief as any).hours;
        (brief.structure as any).sections = ['hero', 'about', 'contact', 'footer'];
      }
      expect(() => validateBrief(brief)).not.toThrow();
    }
  });
});