import { StreamLanguage, type StreamParser } from '@codemirror/language';
import type { ProjectEditorLanguageId } from '../project-language';
import { simpleParser, wordSet } from './common';

const js = wordSet('break case catch class const continue debugger default delete do else export extends finally for from function if import in instanceof let new of return static super switch this throw try typeof var void while with yield async await interface implements private protected public readonly type enum namespace as satisfies');
const jsTypes = wordSet('string number boolean bigint symbol unknown never any void object Array Promise Map Set Date RegExp');
const cssWords = wordSet('and or not only important');

type HtmlState = { comment: boolean };
const htmlParser: StreamParser<HtmlState> = {
  startState: () => ({ comment: false }),
  token(stream, state) {
    if (state.comment) {
      if (stream.skipTo('-->')) { stream.match('-->'); state.comment = false; } else stream.skipToEnd();
      return 'comment';
    }
    if (stream.match('<!--')) { state.comment = true; return 'comment'; }
    if (stream.match(/^<!DOCTYPE\b[^>]*>/iu)) return 'meta';
    if (stream.match(/^<\/?[A-Za-z][\w:-]*/u)) return 'tagName';
    if (stream.match(/^[A-Za-z_:][-\w:.]*(?=\s*=)/u)) return 'propertyName';
    const quote = stream.peek();
    if (quote === '"' || quote === "'") {
      stream.next(); while (!stream.eol()) { const ch = stream.next(); if (ch === quote) break; } return 'string';
    }
    if (stream.match(/^\/?\s*>/u)) return 'punctuation';
    if (stream.eatSpace()) return null;
    stream.next(); return null;
  },
};

const jsonParser: StreamParser<{ blockComment: boolean }> = simpleParser({ keywords: wordSet('true false null') });
const cssParser = simpleParser({ keywords: cssWords, blockComment: ['/*', '*/'] });
const jsParser = simpleParser({ keywords: js, types: jsTypes, lineComment: '//', blockComment: ['/*', '*/'] });

export function projectWebLanguage(id: ProjectEditorLanguageId) {
  if (id === 'html') return StreamLanguage.define(htmlParser);
  if (id === 'css' || id === 'scss') return StreamLanguage.define(cssParser);
  if (id === 'json') return StreamLanguage.define(jsonParser);
  return StreamLanguage.define(jsParser);
}
