import { Type, validKeys } from "./type_utils.ts";

export class InvalidTypeAnnotation extends SyntaxError {
  constructor (value: string, position: number) {
    super(`Could not determine type from \`<: ${value}>\`. (at ${position})`);
  }
}

export class MissingType extends SyntaxError {
  constructor (variable: string, position: number) {
    super(`A type was not given when declaring \`${variable}\`. (at ${position})`);
  }
}

export class InvalidType extends TypeError {
  constructor (expected: Type | string, got: Type | string, position: number) {
    super(`Expected \`${expected}\`, got \`${got}\`. (at ${position})`);
  }
}

export class InvalidSyntaxType extends SyntaxError {
  constructor (expected: string, got: string, position: number) {
    super(`Expected \`<${expected}>\`, got \`<${got}>\`. (at ${position})`);
  }
}

export class InvalidExpression extends SyntaxError {
  constructor (type: string, position: number) {
    super(`Unknown or unsupported expression or literal type \`${type}\`. (at ${position})`);
  } 
}

export class InvalidBinaryOp extends TypeError {
  constructor (a: Type, b: Type, op: string, position: number) {
    super(`Cannot perform operation \`${op}\` on \`${a}\` and \`${b}\`. (at ${position})`);
  }
}

export class UndefinedReference extends ReferenceError {
  constructor (name: string, position: number) {
    super(`\`${name}\` is not defined, or is a builtin that cannot be used in an expression. (at ${position})`);
  }
} 

export class InvalidAssignmentTarget extends SyntaxError {
  constructor (position: number) {
    super(`Left-hand side of assignment must be an \`Identifier\`. Destructuring not supported. (at ${position})`);
  }
}

export class InvalidArgumentCount extends SyntaxError {
  constructor (name: string, count: number, expected: number, position: number) {
    super(`\`${name}\` expects ${expected} arguments, got ${count}. (at ${position})`);
  }
}

export class InvalidAttrOrMeta extends Error {
  constructor (key: string, group: "attr" | "meta", position: number) {
    super(`Expected \`${validKeys[group].join(", ")}\`, got \`${key}\`. (at ${position})`);
  }
}

export class AlreadyDefined extends ReferenceError {
  constructor (decl: string, position: number) {
    super(`\`${decl}\` is already defined. (at ${position})`);
  }
}

export class ForMissingEnd extends SyntaxError {
  constructor (position: number) {
    super(`Missing direction and end in for statement (at ${position})\nSee DOCS.md for more info on for statements.`);
  }
}

export class ForMissingInit extends SyntaxError {
  constructor (position: number) {
    super(`Missing init in for statement (at ${position})\nSee DOCS.md for more info on for statements.`);
  }
}

export class ForVariableMismatch extends SyntaxError {
  constructor (expected: string, got: string, position: number) {
    super(`Expected \`${expected}\`, got \`${got}\` (at ${position})\nSee DOCS.md for more info on for statements.`);
  }
}

export class ForInvalidOperator extends InvalidSyntaxType {
  constructor (op: string, position: number) {
    super("+= | -=", op, position);
    this.message = `Invalid operator in for statement: ${this.message}\nSee DOCS.md for more info on for statements.`;
  }
}