/**
 * liquidTemplateSupport Tests
 *
 * Tests for Liquid template validation and syntax support
 */

import {
  LIQUID_PATTERNS,
  LiquidValidator,
  validateLiquidHTML,
  liquidVSCodeTheme,
  createLiquidExtensions,
  LIQUID_SNIPPETS
} from '../liquidTemplateSupport';

describe('liquidTemplateSupport', () => {
  describe('LIQUID_PATTERNS', () => {
    it('matches Liquid output tags', () => {
      const html = 'Hello {{ customer.name }}!';
      const matches = html.match(LIQUID_PATTERNS.OUTPUT_TAG);

      expect(matches).toBeTruthy();
      expect(matches.length).toBe(1);
      expect(matches[0]).toBe('{{ customer.name }}');
    });

    it('matches Liquid logic tags', () => {
      const html = '{% if condition %}content{% endif %}';
      const matches = html.match(LIQUID_PATTERNS.LOGIC_TAG);

      expect(matches).toBeTruthy();
      expect(matches.length).toBe(2);
      expect(matches[0]).toBe('{% if condition %}');
      expect(matches[1]).toBe('{% endif %}');
    });

    it('matches Liquid comment tags', () => {
      const html = '{% comment %}This is a comment{% endcomment %}';
      const matches = html.match(LIQUID_PATTERNS.COMMENT_TAG);

      expect(matches).toBeTruthy();
      expect(matches.length).toBe(1);
    });

    it('matches Liquid filters', () => {
      const html = '{{ name | capitalize }}';
      const matches = html.match(LIQUID_PATTERNS.FILTER);

      expect(matches).toBeTruthy();
      expect(matches[0]).toContain('capitalize');
    });

    it('matches Liquid keywords', () => {
      const text = 'if for unless endif';
      const matches = text.match(LIQUID_PATTERNS.KEYWORDS);

      expect(matches).toBeTruthy();
      expect(matches.length).toBeGreaterThan(0);
    });

    it('matches Liquid operators', () => {
      const text = 'and or not contains';
      const matches = text.match(LIQUID_PATTERNS.OPERATORS);

      expect(matches).toBeTruthy();
      expect(matches.length).toBeGreaterThan(0);
    });
  });

  describe('LiquidValidator', () => {
    let validator;

    beforeEach(() => {
      validator = new LiquidValidator();
    });

    describe('Basic Validation', () => {
      it('validates valid Liquid template', () => {
        const html = '<p>Hello {{ customer.name }}!</p>';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });

      it('handles empty content', () => {
        const result = validator.validate('');

        expect(result.isValid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });

      it('handles null content', () => {
        const result = validator.validate(null);

        expect(result.isValid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });

      it('handles non-string content', () => {
        const result = validator.validate(123);

        expect(result.isValid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });
    });

    describe('Output Tag Validation', () => {
      it('detects unclosed output tags', () => {
        const html = '<p>Hello {{ customer.name</p>';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors).toHaveLength(1);
        expect(result.errors[0].rule).toBe('liquid-unclosed-output');
        expect(result.errors[0].message).toContain('unclosed');
      });

      it('detects multiple unclosed output tags', () => {
        const html = '<p>{{ name {{ email</p>';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors.length).toBeGreaterThan(0);
      });

      it('validates properly closed output tags', () => {
        const html = '<p>{{ name }} and {{ email }}</p>';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });
    });

    describe('Logic Tag Validation', () => {
      it('detects unclosed logic tags', () => {
        const html = '{% if condition <p>content</p>';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors).toHaveLength(1);
        expect(result.errors[0].rule).toBe('liquid-unclosed-logic');
      });

      it('validates balanced if/endif tags', () => {
        const html = '{% if condition %}content{% endif %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
        expect(result.errors).toHaveLength(0);
      });

      it('detects unmatched endif without if', () => {
        const html = '{% endif %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors[0].rule).toBe('liquid-unexpected-closing');
      });

      it('detects unclosed if tag', () => {
        const html = '{% if condition %}content';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors[0].rule).toBe('liquid-unclosed-tag');
      });

      it('validates balanced for/endfor tags', () => {
        const html = '{% for item in items %}{{ item }}{% endfor %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('detects mismatched tags', () => {
        const html = '{% if condition %}content{% endfor %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors[0].rule).toBe('liquid-mismatched-tags');
      });

      it('validates nested if/endif blocks', () => {
        const html = '{% if outer %}{% if inner %}content{% endif %}{% endif %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('validates case/endcase tags', () => {
        const html = '{% case var %}{% when "a" %}A{% endcase %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('validates unless/endunless tags', () => {
        const html = '{% unless condition %}content{% endunless %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('validates capture/endcapture tags', () => {
        const html = '{% capture my_var %}content{% endcapture %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });
    });

    describe('Nested Braces Validation', () => {
      it('detects nested output braces', () => {
        const html = '{{ outer {{ inner }} }}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors[0].rule).toBe('liquid-nested-braces');
      });

      it('detects nested logic braces', () => {
        const html = '{% outer {% inner %} %}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors[0].rule).toBe('liquid-nested-braces');
      });
    });

    describe('Filter Validation', () => {
      it('detects malformed filters with double pipes', () => {
        const html = '{{ name || }}';
        const result = validator.validate(html);

        expect(result.warnings.length).toBeGreaterThan(0);
        expect(result.warnings[0].rule).toBe('liquid-malformed-filter');
      });

      it('validates common filters', () => {
        const html = '{{ name | capitalize }}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('provides info for uncommon filters', () => {
        const html = '{{ name | custom_filter }}';
        const result = validator.validate(html);

        expect(result.info.length).toBeGreaterThan(0);
        expect(result.info[0].rule).toBe('liquid-filter-usage');
      });

      it('validates chained filters', () => {
        const html = '{{ name | capitalize | truncate: 50 }}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });
    });

    describe('Variable Validation', () => {
      it('warns about potentially undefined variables', () => {
        const html = '{{ undefined }}';
        const result = validator.validate(html);

        expect(result.warnings.length).toBeGreaterThan(0);
        expect(result.warnings[0].rule).toBe('liquid-undefined-variable');
      });

      it('validates normal variable usage', () => {
        const html = '{{ customer.name }}';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });
    });

    describe('Line Number Calculation', () => {
      it('calculates line numbers correctly', () => {
        const html = 'Line 1\nLine 2\nLine 3 {{ unclosed';
        const result = validator.validate(html);

        expect(result.errors[0].line).toBe(3);
      });

      it('handles position 0', () => {
        const lineNum = validator.getLineNumber('test', 0);
        expect(lineNum).toBe(1);
      });

      it('handles negative position', () => {
        const lineNum = validator.getLineNumber('test', -1);
        expect(lineNum).toBe(1);
      });

      it('handles undefined position', () => {
        const lineNum = validator.getLineNumber('test', undefined);
        expect(lineNum).toBe(1);
      });
    });

    describe('Complex Scenarios', () => {
      it('validates complex template with multiple features', () => {
        const html = `
          <div>
            {% if customer %}
              <p>Hello {{ customer.name | capitalize }}!</p>
              {% for item in cart.items %}
                <div>{{ item.title }} - {{ item.price | money }}</div>
              {% endfor %}
            {% endif %}
          </div>
        `;
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });

      it('detects multiple types of errors', () => {
        const html = `
          {% if condition
          {{ unclosed
          {% for item in items %}
        `;
        const result = validator.validate(html);

        expect(result.isValid).toBe(false);
        expect(result.errors.length).toBeGreaterThan(1);
      });

      it('validates Liquid within HTML attributes', () => {
        const html = '<img src="{{ product.image }}" alt="{{ product.title }}">';
        const result = validator.validate(html);

        expect(result.isValid).toBe(true);
      });
    });

    describe('Result Structure', () => {
      it('returns correct result structure', () => {
        const result = validator.validate('<p>Valid</p>');

        expect(result).toHaveProperty('isValid');
        expect(result).toHaveProperty('errors');
        expect(result).toHaveProperty('warnings');
        expect(result).toHaveProperty('info');
        expect(Array.isArray(result.errors)).toBe(true);
        expect(Array.isArray(result.warnings)).toBe(true);
        expect(Array.isArray(result.info)).toBe(true);
      });

      it('includes proper error structure', () => {
        const html = '{{ unclosed';
        const result = validator.validate(html);

        expect(result.errors[0]).toHaveProperty('type');
        expect(result.errors[0]).toHaveProperty('message');
        expect(result.errors[0]).toHaveProperty('line');
        expect(result.errors[0]).toHaveProperty('column');
        expect(result.errors[0]).toHaveProperty('rule');
        expect(result.errors[0]).toHaveProperty('severity');
        expect(result.errors[0]).toHaveProperty('source');
      });
    });
  });

  describe('validateLiquidHTML', () => {
    it('validates HTML with Liquid templates', () => {
      const html = '<p>{{ customer.name }}</p>';
      const result = validateLiquidHTML(html);

      expect(result).toHaveProperty('isValid');
      expect(result).toHaveProperty('errors');
    });

    it('accepts variant parameter', () => {
      const html = '<p>{{ customer.name }}</p>';
      const result = validateLiquidHTML(html, 'inapp');

      expect(result).toBeDefined();
    });

    it('defaults to email variant', () => {
      const html = '<p>{{ customer.name }}</p>';
      const result = validateLiquidHTML(html);

      expect(result).toBeDefined();
    });
  });

  describe('liquidVSCodeTheme', () => {
    it('is defined', () => {
      expect(liquidVSCodeTheme).toBeDefined();
    });

    it('is an object with highlight styles', () => {
      expect(typeof liquidVSCodeTheme).toBe('object');
    });
  });

  describe('createLiquidExtensions', () => {
    it('returns an array of extensions', () => {
      const extensions = createLiquidExtensions();

      expect(Array.isArray(extensions)).toBe(true);
      expect(extensions.length).toBeGreaterThan(0);
    });

    it('includes HTML language support', () => {
      const extensions = createLiquidExtensions();

      expect(extensions).toBeDefined();
      expect(extensions.length).toBeGreaterThanOrEqual(3);
    });
  });

  describe('LIQUID_SNIPPETS', () => {
    it('contains customer snippets', () => {
      expect(LIQUID_SNIPPETS).toHaveProperty('customer_name');
      expect(LIQUID_SNIPPETS).toHaveProperty('customer_email');
      expect(LIQUID_SNIPPETS.customer_name).toContain('{{ customer');
    });

    it('contains logic snippets', () => {
      expect(LIQUID_SNIPPETS).toHaveProperty('if_statement');
      expect(LIQUID_SNIPPETS).toHaveProperty('for_loop');
      expect(LIQUID_SNIPPETS.if_statement).toContain('{% if');
    });

    it('contains filter snippets', () => {
      expect(LIQUID_SNIPPETS).toHaveProperty('date_filter');
      expect(LIQUID_SNIPPETS).toHaveProperty('capitalize_filter');
      expect(LIQUID_SNIPPETS.date_filter).toContain('| date');
    });

    it('contains organization snippets', () => {
      expect(LIQUID_SNIPPETS).toHaveProperty('organization_name');
      expect(LIQUID_SNIPPETS.organization_name).toContain('organization');
    });

    it('all snippets are valid strings', () => {
      Object.values(LIQUID_SNIPPETS).forEach(snippet => {
        expect(typeof snippet).toBe('string');
        expect(snippet.length).toBeGreaterThan(0);
      });
    });
  });

  describe('Edge Cases', () => {
    let validator;

    beforeEach(() => {
      validator = new LiquidValidator();
    });

    it('handles empty Liquid tags', () => {
      const html = '{{ }}';
      const result = validator.validate(html);

      expect(result).toBeDefined();
    });

    it('handles Liquid tags with whitespace', () => {
      const html = '{{   customer.name   }}';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });

    it('handles mixed HTML and Liquid', () => {
      const html = '<div class="test">{{ value }}</div>';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });

    it('handles Liquid in script tags', () => {
      const html = '<script>var x = "{{ value }}";</script>';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });

    it('handles very long content', () => {
      const longContent = '{{ name }}\n'.repeat(1000);
      const result = validator.validate(longContent);

      expect(result).toBeDefined();
    });

    it('handles special characters in Liquid variables', () => {
      const html = '{{ customer["special-key"] }}';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });

    it('handles Liquid comments', () => {
      const html = '{% comment %}This is a comment{% endcomment %}';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });

    it('handles raw tags', () => {
      const html = '{% raw %}{{ this should not be processed }}{% endraw %}';
      const result = validator.validate(html);

      expect(result.isValid).toBe(true);
    });
  });
});

