#pragma once

#include "xtr/core/rslIndex.hpp"
#include "xtr/ui/BuffRichEdit.h"

namespace xtr::ui {

//! Control: Edit RS expression
class RSEdit : public BuffRichEdit {
  const ccl::semantic::RSCore* context{ nullptr };
  EntityUID activeUID{};

  ccl::rslang::Parser parser{};
  std::unique_ptr<ccl::rslang::Auditor> checker{ nullptr };
  CString astText{};

  StrPos prefixLen{ 0 };
  bool navigatorEnabled{ false };
  std::optional<ccl::rslang::SyntaxTree::Cursor> activeNode{};

public:
  RSEdit();
  RSEdit(const RSEdit&) = delete;
  RSEdit& operator=(const RSEdit&) = delete;

public:
  void InputBrackets();
  void InputParenthesis();
  void InputToken(ccl::rslang::TokenID token);
  void Init(const ccl::semantic::RSCore& cntxt, EntityUID active);

private:
  void PreSubclassWindow() override;
  BOOL PreTranslateMessage(MSG* pMsg) override;

DECLARE_MESSAGE_MAP()
  afx_msg void OnChar(uint32_t nChar, uint32_t nRepCnt, uint32_t nFlags);
  afx_msg void OnSysChar(uint32_t nChar, uint32_t nRepCnt, uint32_t nFlags);
  afx_msg void OnKeyDown(uint32_t nChar, uint32_t nRepCnt, uint32_t nFlags);

private:
  BOOL UpdateAST();

  struct BracketPair {
    std::optional<StrPos> left{ std::nullopt };
    std::optional<StrPos> right{ std::nullopt };

    [[nodiscard]] StrRange Range() const {
      return StrRange{ left.value(), right.value() };
    }
    [[nodiscard]] bool IsNull() const noexcept {
      return !left.has_value() && !right.has_value();
    }
    [[nodiscard]] bool IsCorrect() const noexcept {
      return left.has_value() && right.has_value();
    }
  };

  void UpdateFormatItems() override;
  void AdditionalFormat() override;
  [[nodiscard]] CString GenerateToolTipText() override;

  void FormatBracketsAround(StrPos caretPos);
  void FormatSelectedBlock(StrRange selection);
  void FormatIdentifier(ccl::rslang::TokenID tid, StrRange pos);
  void FormatBracket(int32_t level, StrRange pos);
  
  void SelectPairedBracket(StrPos caretPos);
  [[nodiscard]] std::optional<BracketPair> GetBracketPair(StrPos pos, TCHAR leftBracket, TCHAR rightBracket) const;
  
  void FormatIndex(ccl::rslang::TokenID tid, StrRange pos, StrPos prefix, BOOL subscript);
  void AddReference();

  void InsertRSText(CString text, StrRange sel);

  BOOL NavigatorOn();
  BOOL MoveUp() noexcept;
  BOOL MoveDown();
  BOOL MoveLeft();
  BOOL MoveRight();
};

} // namespace xtr::ui