/**
 * Template System Integration Tests
 * 템플릿 시스템의 기본 기능과 통합 테스트
 */

import { describe, test, expect } from "@jest/globals";
import {
  ServiceTier,
  ComponentType,
  TIER_COMPONENT_MAP,
  TIER_COMPONENT_LIMITS,
  isComponentAllowedInTier,
  getAvailableComponentsForTier,
  getMinimumTierForComponent,
  getNewComponentsAfterUpgrade,
  calculateTemplateComplexity,
  TIER_INFO,
  COMPONENT_COMPLEXITY,
  RECOMMENDED_COMPONENT_SETS,
} from "../index";

describe("Template System Core Functions", () => {
  describe("Tier Component Validation", () => {
    test("should validate components for Starter tier", () => {
      expect(
        isComponentAllowedInTier(ComponentType.HERO, ServiceTier.STARTER)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.ABOUT, ServiceTier.STARTER)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.CONTACT, ServiceTier.STARTER)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.FOOTER, ServiceTier.STARTER)
      ).toBe(true);

      // These should not be allowed in Starter
      expect(
        isComponentAllowedInTier(ComponentType.SERVICES, ServiceTier.STARTER)
      ).toBe(false);
      expect(
        isComponentAllowedInTier(
          ComponentType.TESTIMONIALS,
          ServiceTier.STARTER
        )
      ).toBe(false);
      expect(
        isComponentAllowedInTier(ComponentType.TEAM, ServiceTier.STARTER)
      ).toBe(false);
    });

    test("should validate components for Standard tier", () => {
      expect(
        isComponentAllowedInTier(ComponentType.SERVICES, ServiceTier.STANDARD)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(
          ComponentType.TESTIMONIALS,
          ServiceTier.STANDARD
        )
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.PORTFOLIO, ServiceTier.STANDARD)
      ).toBe(true);

      // Plus tier exclusive components should not be allowed
      expect(
        isComponentAllowedInTier(ComponentType.TEAM, ServiceTier.STANDARD)
      ).toBe(false);
      expect(
        isComponentAllowedInTier(ComponentType.PRICING, ServiceTier.STANDARD)
      ).toBe(false);
      expect(
        isComponentAllowedInTier(ComponentType.FAQ, ServiceTier.STANDARD)
      ).toBe(false);
    });

    test("should validate components for Plus tier", () => {
      expect(
        isComponentAllowedInTier(ComponentType.TEAM, ServiceTier.PLUS)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.PRICING, ServiceTier.PLUS)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.FAQ, ServiceTier.PLUS)
      ).toBe(true);
      expect(
        isComponentAllowedInTier(ComponentType.BLOG, ServiceTier.PLUS)
      ).toBe(true);
    });
  });

  describe("Component Limits", () => {
    test("should have correct component limits per tier", () => {
      expect(TIER_COMPONENT_LIMITS[ServiceTier.STARTER]).toBe(4);
      expect(TIER_COMPONENT_LIMITS[ServiceTier.STANDARD]).toBe(7);
      expect(TIER_COMPONENT_LIMITS[ServiceTier.PLUS]).toBe(Infinity);
    });

    test("should match component counts with tier limits", () => {
      expect(TIER_COMPONENT_MAP[ServiceTier.STARTER].length).toBe(4);
      expect(TIER_COMPONENT_MAP[ServiceTier.STANDARD].length).toBe(7);
      expect(TIER_COMPONENT_MAP[ServiceTier.PLUS].length).toBe(11);
    });
  });

  describe("Available Components", () => {
    test("should return correct available components for each tier", () => {
      const starterComponents = getAvailableComponentsForTier(
        ServiceTier.STARTER
      );
      expect(starterComponents).toHaveLength(4);
      expect(starterComponents).toContain(ComponentType.HERO);
      expect(starterComponents).toContain(ComponentType.ABOUT);

      const standardComponents = getAvailableComponentsForTier(
        ServiceTier.STANDARD
      );
      expect(standardComponents).toHaveLength(7);
      expect(standardComponents).toContain(ComponentType.SERVICES);
      expect(standardComponents).toContain(ComponentType.TESTIMONIALS);

      const plusComponents = getAvailableComponentsForTier(ServiceTier.PLUS);
      expect(plusComponents).toHaveLength(11);
      expect(plusComponents).toContain(ComponentType.TEAM);
      expect(plusComponents).toContain(ComponentType.PRICING);
    });
  });

  describe("Minimum Tier Requirements", () => {
    test("should return correct minimum tier for basic components", () => {
      expect(getMinimumTierForComponent(ComponentType.HERO)).toBe(
        ServiceTier.STARTER
      );
      expect(getMinimumTierForComponent(ComponentType.ABOUT)).toBe(
        ServiceTier.STARTER
      );
      expect(getMinimumTierForComponent(ComponentType.CONTACT)).toBe(
        ServiceTier.STARTER
      );
      expect(getMinimumTierForComponent(ComponentType.FOOTER)).toBe(
        ServiceTier.STARTER
      );
    });

    test("should return correct minimum tier for standard components", () => {
      expect(getMinimumTierForComponent(ComponentType.SERVICES)).toBe(
        ServiceTier.STANDARD
      );
      expect(getMinimumTierForComponent(ComponentType.TESTIMONIALS)).toBe(
        ServiceTier.STANDARD
      );
      expect(getMinimumTierForComponent(ComponentType.PORTFOLIO)).toBe(
        ServiceTier.STANDARD
      );
    });

    test("should return correct minimum tier for plus components", () => {
      expect(getMinimumTierForComponent(ComponentType.TEAM)).toBe(
        ServiceTier.PLUS
      );
      expect(getMinimumTierForComponent(ComponentType.PRICING)).toBe(
        ServiceTier.PLUS
      );
      expect(getMinimumTierForComponent(ComponentType.FAQ)).toBe(
        ServiceTier.PLUS
      );
      expect(getMinimumTierForComponent(ComponentType.BLOG)).toBe(
        ServiceTier.PLUS
      );
    });
  });

  describe("Tier Upgrades", () => {
    test("should return new components after upgrade from Starter to Standard", () => {
      const newComponents = getNewComponentsAfterUpgrade(
        ServiceTier.STARTER,
        ServiceTier.STANDARD
      );

      expect(newComponents).toHaveLength(3);
      expect(newComponents).toContain(ComponentType.SERVICES);
      expect(newComponents).toContain(ComponentType.TESTIMONIALS);
      expect(newComponents).toContain(ComponentType.PORTFOLIO);
    });

    test("should return new components after upgrade from Standard to Plus", () => {
      const newComponents = getNewComponentsAfterUpgrade(
        ServiceTier.STANDARD,
        ServiceTier.PLUS
      );

      expect(newComponents).toHaveLength(4);
      expect(newComponents).toContain(ComponentType.TEAM);
      expect(newComponents).toContain(ComponentType.PRICING);
      expect(newComponents).toContain(ComponentType.FAQ);
      expect(newComponents).toContain(ComponentType.BLOG);
    });

    test("should return new components after upgrade from Starter to Plus", () => {
      const newComponents = getNewComponentsAfterUpgrade(
        ServiceTier.STARTER,
        ServiceTier.PLUS
      );

      expect(newComponents).toHaveLength(7);
      expect(newComponents).toContain(ComponentType.SERVICES);
      expect(newComponents).toContain(ComponentType.TEAM);
      expect(newComponents).toContain(ComponentType.PRICING);
    });
  });

  describe("Template Complexity", () => {
    test("should calculate correct complexity for simple template", () => {
      const simpleTemplate = [
        ComponentType.HERO,
        ComponentType.ABOUT,
        ComponentType.CONTACT,
        ComponentType.FOOTER,
      ];

      const complexity = calculateTemplateComplexity(simpleTemplate);
      const expectedComplexity = 1 + 1 + 2 + 1; // hero + about + contact + footer
      expect(complexity).toBe(expectedComplexity);
    });

    test("should calculate correct complexity for complex template", () => {
      const complexTemplate = [
        ComponentType.HERO,
        ComponentType.SERVICES,
        ComponentType.PRICING,
        ComponentType.TEAM,
        ComponentType.FAQ,
      ];

      const complexity = calculateTemplateComplexity(complexTemplate);
      const expectedComplexity = 1 + 3 + 5 + 4 + 3; // hero + services + pricing + team + faq
      expect(complexity).toBe(expectedComplexity);
    });
  });

  describe("Tier Information", () => {
    test("should have correct tier information structure", () => {
      expect(TIER_INFO[ServiceTier.STARTER]).toHaveProperty("name");
      expect(TIER_INFO[ServiceTier.STARTER]).toHaveProperty("description");
      expect(TIER_INFO[ServiceTier.STARTER]).toHaveProperty("price");
      expect(TIER_INFO[ServiceTier.STARTER]).toHaveProperty("maxComponents");
      expect(TIER_INFO[ServiceTier.STARTER]).toHaveProperty("features");
    });

    test("should have correct pricing structure", () => {
      expect(TIER_INFO[ServiceTier.STARTER].price).toHaveProperty("monthly");
      expect(TIER_INFO[ServiceTier.STARTER].price).toHaveProperty("yearly");
      expect(typeof TIER_INFO[ServiceTier.STARTER].price.monthly).toBe(
        "number"
      );
      expect(typeof TIER_INFO[ServiceTier.STARTER].price.yearly).toBe("number");
    });
  });

  describe("Component Complexity Constants", () => {
    test("should have complexity ratings for all component types", () => {
      const allComponentTypes = Object.values(ComponentType);

      allComponentTypes.forEach((componentType) => {
        expect(COMPONENT_COMPLEXITY).toHaveProperty(componentType);
        expect(typeof COMPONENT_COMPLEXITY[componentType]).toBe("number");
        expect(COMPONENT_COMPLEXITY[componentType]).toBeGreaterThan(0);
        expect(COMPONENT_COMPLEXITY[componentType]).toBeLessThanOrEqual(5);
      });
    });
  });

  describe("Recommended Component Sets", () => {
    test("should have valid component sets for different use cases", () => {
      const useCases = Object.keys(RECOMMENDED_COMPONENT_SETS);
      expect(useCases).toContain("landing-page");
      expect(useCases).toContain("corporate-website");
      expect(useCases).toContain("portfolio-site");
      expect(useCases).toContain("saas-product");
    });

    test("should have valid components in recommended sets", () => {
      Object.values(RECOMMENDED_COMPONENT_SETS).forEach((componentSet) => {
        expect(Array.isArray(componentSet)).toBe(true);
        expect(componentSet.length).toBeGreaterThan(0);

        componentSet.forEach((component) => {
          expect(Object.values(ComponentType)).toContain(component);
        });
      });
    });

    test("landing page set should be suitable for Standard tier", () => {
      const landingPageComponents = RECOMMENDED_COMPONENT_SETS["landing-page"];
      const standardComponents = getAvailableComponentsForTier(
        ServiceTier.STANDARD
      );

      landingPageComponents.forEach((component) => {
        expect(standardComponents).toContain(component);
      });
    });
  });
});

describe("Template System Integration", () => {
  test("should maintain consistency across tier hierarchies", () => {
    // Starter components should be included in Standard
    const starterComponents = TIER_COMPONENT_MAP[ServiceTier.STARTER];
    const standardComponents = TIER_COMPONENT_MAP[ServiceTier.STANDARD];

    starterComponents.forEach((component) => {
      expect(standardComponents).toContain(component);
    });

    // Standard components should be included in Plus
    const plusComponents = TIER_COMPONENT_MAP[ServiceTier.PLUS];

    standardComponents.forEach((component) => {
      expect(plusComponents).toContain(component);
    });
  });

  test("should have unique components per tier upgrade", () => {
    const starterToStandard = getNewComponentsAfterUpgrade(
      ServiceTier.STARTER,
      ServiceTier.STANDARD
    );
    const standardToPlus = getNewComponentsAfterUpgrade(
      ServiceTier.STANDARD,
      ServiceTier.PLUS
    );

    // Should not have overlapping new components
    const intersection = starterToStandard.filter((component) =>
      standardToPlus.includes(component)
    );
    expect(intersection).toHaveLength(0);
  });
});
