import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { BootstrapConfig } from '../../../shared/models/config';
import { WidgetManifestService } from '../../../widgets/registry/widget-manifest.service';
import { WidgetManifestFile } from '../../../widgets/contracts/widget-manifest.contract';
import { ProjectValidator } from './project-validator.service';

function makeBootstrap(): BootstrapConfig {
  return {
    branding: { logoUrl: 'logo.png' },
    localization: { supportedLocales: ['en'], defaultLocale: 'en' },
    tenant: { websiteBaseUrl: 'https://dexar.market' },
    staticPages: {},
    pages: [
      {
        key: 'home',
        route: { path: '/' },
        sections: [
          {
            order: 0,
            layout: { strategy: 'stack' },
            widgets: [{ id: 'w1', type: 'hero', version: '1', props: {} }],
          },
        ],
      },
    ],
    navigation: { header: [], footer: [] },
    theme: {
      palette: {
        primary: '#497671',
        secondary: '#a1b4b5',
        accent: '#a7ceca',
        success: '#10b981',
        warning: '#f59e0b',
        danger: '#ef4444',
        info: '#3b82f6',
        textPrimary: '#1e3c38',
        textSecondary: '#667a77',
        backgroundPrimary: '#ffffff',
        backgroundSecondary: '#f5f5f5',
        border: '#d3dad9',
      },
    },
    layout: { type: 'default' },
  } as unknown as BootstrapConfig;
}

describe('ProjectValidator', () => {
  let validator: ProjectValidator;

  beforeEach(() => {
    TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()] });
    validator = TestBed.inject(ProjectValidator);
  });

  it('reports no issues for a valid baseline config', () => {
    expect(validator.validate(makeBootstrap())).toEqual([]);
  });

  it('flags an invalid palette color against its field key with error severity', () => {
    const bootstrap = makeBootstrap();
    (bootstrap.theme.palette as unknown as Record<string, string>)['primary'] = '#zzz';
    const issues = validator.validate(bootstrap);
    const color = issues.find(issue => issue.code === 'invalid-colors');
    expect(color).toBeDefined();
    expect(color?.fieldKey).toBe('theme.palette.primary');
    expect(color?.section).toBe('theme');
    expect(color?.severity).toBe('error');
  });

  it('flags a missing logo mapped to the branding field', () => {
    const bootstrap = makeBootstrap();
    bootstrap.branding.logoUrl = '';
    const issue = validator.validate(bootstrap).find(i => i.code === 'missing-logo');
    expect(issue?.fieldKey).toBe('branding.logoUrl');
    expect(issue?.severity).toBe('error');
  });

  it('flags a malformed widget (missing version) as invalid-widget-config', () => {
    const bootstrap = makeBootstrap();
    delete (bootstrap.pages[0].sections[0].widgets[0] as { version?: string }).version;
    const issue = validator.validate(bootstrap).find(i => i.code === 'invalid-widget-config');
    expect(issue).toBeDefined();
    expect(issue?.section).toBe('widgets');
    expect(issue?.severity).toBe('error');
  });

  it('flags duplicate page routes as a non-blocking warning', () => {
    const bootstrap = makeBootstrap();
    bootstrap.pages.push({ ...bootstrap.pages[0], key: 'about', route: { path: '/about' } });
    bootstrap.pages.push({ ...bootstrap.pages[0], key: 'about-copy', route: { path: '/about' } });
    const issue = validator.validate(bootstrap).find(i => i.code === 'duplicate-routes');
    expect(issue).toBeDefined();
    expect(issue?.severity).toBe('warning');
  });

  it('rejects an invalid website URL', () => {
    const bootstrap = makeBootstrap();
    bootstrap.tenant.websiteBaseUrl = 'dexar.market';
    const issue = validator.validate(bootstrap).find(i => i.code === 'invalid-url');
    expect(issue?.fieldKey).toBe('tenant.websiteBaseUrl');
  });

  describe('widgetSettingsSchema (against widget-manifest settingsSchema)', () => {
    const manifest: WidgetManifestFile = {
      widgets: [
        {
          type: 'hero',
          version: '1',
          componentKey: 'hero',
          supportedLayouts: ['hero'],
          supportedDataSources: [],
          settingsSchema: { type: 'object', properties: { title: { type: 'string' } }, required: ['title'] },
          defaultSettings: {},
        },
      ],
    };

    it('does nothing before the manifest has ever loaded (getManifestSnapshot() is null)', () => {
      const bootstrap = makeBootstrap();
      bootstrap.pages[0].sections[0].widgets[0].props = {};
      expect(validator.validate(bootstrap).find(i => i.code === 'invalid-widget-settings')).toBeUndefined();
    });

    it('flags a widget missing a required settingsSchema property once the manifest is loaded', () => {
      spyOn(TestBed.inject(WidgetManifestService), 'getManifestSnapshot').and.returnValue(manifest);
      const bootstrap = makeBootstrap();
      bootstrap.pages[0].sections[0].widgets[0].props = {};

      const issue = validator.validate(bootstrap).find(i => i.code === 'invalid-widget-settings');
      expect(issue).toBeDefined();
      expect(issue?.section).toBe('widgets');
      expect(issue?.severity).toBe('warning');
    });

    it('passes when the widget props satisfy the manifest settingsSchema', () => {
      spyOn(TestBed.inject(WidgetManifestService), 'getManifestSnapshot').and.returnValue(manifest);
      const bootstrap = makeBootstrap();
      bootstrap.pages[0].sections[0].widgets[0].props = { title: 'Welcome' };

      expect(validator.validate(bootstrap).find(i => i.code === 'invalid-widget-settings')).toBeUndefined();
    });
  });
});
