import ts from 'typescript';
import { UserTranspileIntention } from '../../cli/args.js';

/**
 *
 * ### Warning
 *
 * Do NOT try to add any getter/setter here.
 * Generator context uses spread syntax to copy, so setter and getter are not copied.
 * Since it is used as a data class (a plain object), maybe it should be better if it remains simple.
 */
type GeneratorContext = {
    /** The compiler program of the TypeScript Compiler API. */
    readonly compiler_program: ts.Program;
    /** The user option passed from command line. */
    readonly transpiler_option: TranspilerOption;
    /**
     * Level of indent. Used for generating space for SCLang (**not** indent level in TypeScript).
     *
     * ### Guidelines for Indentation (advise from ChatGPT)
     *
     * * Always Explicit: Add indentation explicitly at the root of each converter,
     *    only if `is_standalone_statement` is true.
     * * Child Responsibility: Nested converters should not add indentation;
     *    they assume the parent already handled it.
     */
    indent_level: number;
    /**
     * If generating contents inside a class, this
     */
    class_info: {
        /** Name of current class. */
        name: string;
        /** Name of the super class. */
        super_class_name: string;
    };
    /**
     * Whether generating a SuperCollider's class method.
     * Since in SCLang, method can have `^` as `return` in TypeScript.
     */
    is_generating_method: boolean;
    /**
     * Whether generating a SuperCollider's class constructor.
     * Since in SCLang, constructor must return the instance built.
     *
     * Related `tstosc` tags: `tstosc__built_instance`.
     */
    is_generating_constructor: boolean;
    /**
     * Whether the identifier is a class.
     */
    is_generating_class_name: boolean;
    /**
     * Whether generating a property/method object literal in TypeScript.
     */
    is_generating_member_of_object_literal: boolean;
    /**
     * Whether in a function body that contains an early-return.
     * Notice that this value is `false` when inside a method.
     */
    with_early_return: boolean;
    /**
     * Whether a loop has `continue` or `break` statement.
     *
     * `null` if current context is not in a loop body,
     * so no need to check.
     */
    with_loop_interrupt: boolean | null;
    /**
     * The label of current statement.
     * Will be empty (`""`) if no available label.
     */
    statement_label: string;
    /**
     * This will affect the generation of statement in label ending condition.
     * If current loop is a nested loop (inner loop), then use `loop_end.()` to exit, else `^nil`.
     */
    is_nested_loop: boolean;
    /**
     * Semantic meaning of `break`.
     */
    break_means: "nothing" | "end_switch_case" | "stop_a_loop";
    /**
     * Semantic meaning of `super`.
     */
    super_means: "nothing" | "constructor" | "class_name" | "as_it_is";
    /**
     * This affects how `this` is converted:
     * * `"parameter"`: `tstosc__this_param`.
     * * `"built_instance"`: `tstosc__built_instance`
     * * `"itself"`: `this`.
     */
    this_coming_from: "nothing" | "object_literal_parameter" | "built_instance" | "itself";
    /**
     * A dictionary storing the `tstosc` generated temporary name for some expression,
     *  such as for postfix-self-increment (e.g. `a++`).
     * When transpiling, expression that stores in this dict, when condition fulfilled,
     *  should be replaced by the name stored in this dict (and/or with some additional process).
     *
     * TODO: Should be cleared after leaving a scope.
     */
    expression_temporise_dict: Map<ts.Expression, string>;
    /**
     * Whether stand-alone as a statement occupying one or more lines. Opposite to `at_value_position`.
     * When stand-alone, in most condition, it occupies the whole line, or multiple lines.
     * Indentation should be made at that time.
     *
     * Will be `true` at the initial state of generating.
     */
    is_standalone_statement: boolean;
    /** Create a new context with `indent_level` plus `level` (default `1`). */
    indent: (level?: number) => GeneratorContext;
    /** Create a new context with `indent_level` minus `level` (default `1`). */
    outdent: (level?: number) => GeneratorContext;
    /**
     * Create a new context with
     * `class_info: { name: info.name, super_class_name: returnUndefIfEmpty(info.super_class_name) ?? "Object" }`.
     */
    withClassInfo: (info: {
        name: string;
        super_class_name?: string;
    }) => GeneratorContext;
    /** Create a new context with `at_value_position = value ?? true`. */
    atValuePosition: (value?: boolean) => GeneratorContext;
    /** Create a new context with `is_standalone_statement = value ?? true`. */
    isStandalongStatement: (value?: boolean) => GeneratorContext;
    /** Create a new context with `is_generating_method = value ?? true`. */
    willGenerateMethod: (value?: boolean) => GeneratorContext;
    /** Create a new context with `is_generating_constructor = value ?? true`. */
    willGenerateConstructor: (value?: boolean) => GeneratorContext;
    /** Create a new context with `is_generating_class_name = value ?? true`. */
    willGenerateClassName: (value?: boolean) => GeneratorContext;
    /** Create a new context with `is_generating_object_literal = value ?? true`. */
    willGenerateMemberOfObjectLiteral: (value?: boolean) => GeneratorContext;
    /** Create a new context with `with_early_return = value ?? true`. */
    withEarlyReturn: (value?: boolean) => GeneratorContext;
    /** Create a new context with `with_loop_interrupt = value ?? true`. */
    withLoopInterrupt: (value?: boolean) => GeneratorContext;
    /** Create a new context with `statement_label = value`. */
    withStatementLabel: (value: string) => GeneratorContext;
    /** Create a new context with `statement_label = ""`. */
    clearedStatementLabel: () => GeneratorContext;
    /** Create a new context with `is_nested_loop = value ?? true`. */
    isNestedLoop: (value?: boolean) => GeneratorContext;
    /** Create a new context with `break_means = value`. */
    makeBreakMeans: (value: GeneratorContext["break_means"]) => GeneratorContext;
    /** Create a new context with `super_means = value`. */
    makeSuperMeans: (value: GeneratorContext["super_means"]) => GeneratorContext;
    /** Create a new context with `this_coming_from = value`. */
    makeThisComingFrom: (value: GeneratorContext["this_coming_from"]) => GeneratorContext;
} & ExceptionalSyntax;
type ExceptionalSyntax = {
    /**
     * Whether this file contains unhandled self-increment or self-decrement operator usage,
     *  such as `a++` or `--a`.
     *
     * If wrap-content is generated, this should be set to `false`.
     */
    has_unhandled_self_indecr_operator: boolean;
};
type TranspilerOption = Omit<UserTranspileIntention, "type">;
declare const default_transpiler_option: TranspilerOption;
/**
 * ### Warning
 *
 * Notice that default context's `compiler_program` is a empty program.
 */
declare const default_generator_context: GeneratorContext;

export { type ExceptionalSyntax, type GeneratorContext, type TranspilerOption, default_generator_context, default_transpiler_option };
