unit uGeneral;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TabControl,
  FMX.Controls.Presentation, FMX.StdCtrls, System.ImageList, FMX.ImgList,
  FMX.Styles,
  fSettings, fAI, fNotify, fAutoActions, fChatOBS, FMX.ListBox, fLog, uRecords,
  System.IOUtils, fCommands, uDataBase, FMX.Edit, FMX.Colors, FMX.SpinBox,
  windows;

type
  TForm1 = class(TForm)
    V: TTabControl;
    TabItem1: TTabItem;
    TabItem2: TTabItem;
    TabItem3: TTabItem;
    TabItem4: TTabItem;
    fSettings: TfrSettings;
    ImageList1: TImageList;
    TabItem5: TTabItem;
    Panel1: TPanel;
    btnConnecting: TButton;
    Label2: TLabel;
    Label3: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    aiConnecting: TAniIndicator;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    frAI1: TfrAI;
    TabItem6: TTabItem;
    TabItem7: TTabItem;
    TabItem8: TTabItem;
    TabItem9: TTabItem;
    frNotify1: TfrNotify;
    Label1: TLabel;
    Label4: TLabel;
    Label13: TLabel;
    Label14: TLabel;
    frAutoActions1: TfrAutoActions;
    frChatOBS1: TfrChatOBS;
    frLog1: TfrLog;
    cbTheme: TComboBox;
    Label15: TLabel;
    frCommands1: TfrCommands;
    procedure Label14DblClick(Sender: TObject);
    procedure Label13DblClick(Sender: TObject);
    procedure Label4DblClick(Sender: TObject);
    procedure cbThemeChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure ReadDB();
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  myConst: TConst;
  db: TSettingsDatabase;
  appconst: TBotAppCfg;

implementation

{$R *.fmx}

procedure TForm1.cbThemeChange(Sender: TObject);
begin
  cbTheme.ItemIndex := cbTheme.Items.IndexOf(cbTheme.text);
  if cbTheme.ItemIndex <> -1 then
    TStyleManager.SetStyleFromFile(myConst.stlPath + cbTheme.text);
  // db.WriteSetting('cbTheme', inttostr(cbTheme.ItemIndex));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Path: string;
  SearchRec: TSearchRec;

  function GetPathToTestExe: string; // вернет папку romaming
  begin
    Result := GetEnvironmentVariable('APPDATA');
    if Result <> '' then
      Result := IncludeTrailingPathDelimiter(Result);
  end;

begin

  myConst.GeneralPath := ExtractFilePath(ParamStr(0));
  myConst.AppDataPath := GetPathToTestExe + 'TTW_Bot\';

  if not DirectoryExists(myConst.AppDataPath) then
    CreateDir(myConst.AppDataPath);

  myConst.DBPath := myConst.AppDataPath + 'settings.db';

  if not DirectoryExists(myConst.AppDataPath + 'fonts') then
    CreateDir(myConst.AppDataPath + 'fonts');
  myConst.fontsPath := myConst.AppDataPath + 'fonts\';

  if not DirectoryExists(myConst.AppDataPath + 'imgs') then
    CreateDir(myConst.AppDataPath + 'imgs');
  myConst.imgsPath := myConst.AppDataPath + 'imgs\';

  if not DirectoryExists(myConst.AppDataPath + 'sounds') then
    CreateDir(myConst.AppDataPath + 'sounds');
  myConst.soundsPath := myConst.AppDataPath + 'sounds\';

  if not DirectoryExists(myConst.AppDataPath + 'stl') then
    CreateDir(myConst.AppDataPath + 'stl');
  myConst.stlPath := myConst.AppDataPath + 'stl\';

  if not DirectoryExists(myConst.AppDataPath + 'ytSongs') then
    CreateDir(myConst.AppDataPath + 'ytSongs');
  myConst.ytSongsPath := myConst.AppDataPath + 'ytSongs\';

  myConst.PublicPlay := myConst.GeneralPath + 'PublicPlay.exe';
  myConst.SilentPlay := myConst.GeneralPath + 'SilentPlayer.exe';
  myConst.ytPlay := myConst.GeneralPath + 'Player.exe';
  myConst.cfg1 := myConst.GeneralPath + 'botapp.cfg';

  db := TSettingsDatabase.Create(myConst.DBPath);

  ReadDB;

  for Path in TDirectory.GetFiles(myConst.stlPath) do
    cbTheme.Items.Add(ExtractFileName(Path));
  cbTheme.ItemIndex := strtoint(db.ReadSetting('cbTheme', '-1'));

end;

procedure TForm1.Label13DblClick(Sender: TObject);
begin
  // https://www.twitch.tv/kuznecogr
end;

procedure TForm1.Label14DblClick(Sender: TObject);
begin
  // https://www.flaticon.com/ru/authors/karacis

end;

procedure TForm1.Label4DblClick(Sender: TObject);
begin
  // https://www.twitch.tv/incadence
end;

procedure TForm1.ReadDB;
var
  I: Integer;
  c: TComponent;
  sl: TStringList;

  SavedColor: TAlphaColor;

  ColorStr: string;

  function XorDecryptToStrings(const InputFile, Key: string): TStrings;
  var
    InStream: TFileStream;
    MemStream: TMemoryStream;
    KeyBytes: TBytes;
    KeyLen, KeyIndex: Integer;
    B: Byte;
  begin
    // Преобразуем ключ в байты с использованием ANSI кодировки
    KeyBytes := TEncoding.ANSI.GetBytes(Key);
    KeyLen := Length(KeyBytes);
    if KeyLen = 0 then
      raise Exception.Create('Ключ не может быть пустым');

    InStream := TFileStream.Create(InputFile, fmOpenRead);
    try
      MemStream := TMemoryStream.Create;
      try
        KeyIndex := 0;
        // Расшифровываем данные и записываем в поток в памяти
        while InStream.Position < InStream.Size do
        begin
          InStream.ReadBuffer(B, 1);
          B := B xor KeyBytes[KeyIndex];
          MemStream.WriteBuffer(B, 1);
          KeyIndex := (KeyIndex + 1) mod KeyLen;
        end;
        // Преобразуем данные из потока в TStrings
        MemStream.Position := 0; // Сбрасываем позицию для чтения
        Result := TStringList.Create;
        try
          // Используем ANSI кодировку для преобразования байтов в строку
          Result.LoadFromStream(MemStream, TEncoding.ANSI);
        except
          // В случае ошибки освобождаем ресурсы и пробрасываем исключение
          Result.Free;
          raise;
        end;
      finally
        MemStream.Free;
      end;
    finally
      InStream.Free;
    end;
  end;

begin
  for I := 0 to fSettings.ComponentCount - 1 do
  begin
    c := fSettings.components[I];
    if c is TEdit then
    begin
      TEdit(c).text := db.ReadSetting(TEdit(c).Name);
    end;
    if c is TCheckBox then
    begin
      TCheckBox(c).IsChecked := (db.ReadSetting(TCheckBox(c).Name) = 'True');
    end;
  end;
  db.FChannel := fSettings.edtChannel.text;

  db.LoadGridFromTable('sgRandomInt', frCommands1.sgRandomInt);
  db.LoadGridFromTable('sgCommands', frCommands1.sgCommands);
  db.LoadGridFromTable('sgSAFiles', frCommands1.sgSAFiles);
  db.LoadGridFromTable('sgTFiles', frCommands1.sgTFiles);
  db.LoadGridFromTable('sgAIGen', frCommands1.sgAIGen);

  db.getGroupName(frCommands1.lbRandomGroup.Items);

  if FileExists(myConst.cfg1) then
  begin

    sl := TStringList.Create;

    try
      sl.Assign(XorDecryptToStrings(myConst.cfg1, 'fgvasrgEFAXFAFAS'));
      for I := 0 to sl.Count - 1 do
      begin
        var
        eqPos := Pos('=', sl[I]);
        if eqPos > 0 then
        begin
          var
          Key := Trim(Copy(sl[I], 1, eqPos - 1));
          var
          Value := Trim(Copy(sl[I], eqPos + 1, MaxInt));

          // Распределяем значения по переменным
          if Key = 'k1' then
          begin
            appconst.TTV_ClientID := Value;
          end
          else if Key = 'k2' then
          begin
            appconst.AI_GigaChat_AC := Value;
          end
          else if Key = 'k3' then
          begin
            appconst.AI_GigaChat_ClientID := Value;
          end
          else if Key = 'k4' then
          begin
            appconst.AI_ChatGPT_Token := Value;
          end
          else if Key = 'k5' then
          begin
            appconst.AI_DeepSeec_Token := Value;
          end
          else if Key = 'k6' then
          begin
            appconst.DA_ClientID := Value;
          end
          else if Key = 'k7' then
          begin
            appconst.DA_Sicret := Value;
          end
          else if Key = 'k8' then
          begin
            appconst.DA_URL := Value;
          end
        end;
      end;
      if appconst.TTV_ClientID <> '' then
      begin
        fSettings.btnGetClientID.Visible := True;
      end;
      if ((appconst.AI_GigaChat_AC <> '') and (appconst.AI_GigaChat_ClientID <>
        '')) or (appconst.AI_ChatGPT_Token <> '') or
        (appconst.AI_DeepSeec_Token <> '') then
      begin
        frAI1.btnGetAIDef.Visible := True;
      end;
      if ((appconst.DA_ClientID <> '') and (appconst.DA_Sicret <> '') and
        (appconst.DA_URL <> '')) then
      begin
        fSettings.btnGetDADef.Visible := True;
      end;

    finally
      sl.Free;
    end;
  end;

  for I := 0 to frChatOBS1.ComponentCount - 1 do
  begin
    c := frChatOBS1.components[I];
    if c is TComboBox then
    begin
      TComboBox(c).ItemIndex :=
        strtoint(db.ReadSetting(TComboBox(c).Name, '0'));
    end;
    if c is TColorComboBox then
    begin
      TColorComboBox(c).ItemIndex :=
        strtoint(db.ReadSetting(TComboBox(c).Name, '147'));
    end;
    if c is TSpinBox then
    begin
      if TSpinBox(c).Name = 'sbWebServerPort' then
        TSpinBox(c).text := db.ReadSetting(TSpinBox(c).Name, '8080');
      TSpinBox(c).text := db.ReadSetting(TSpinBox(c).Name, '1');
    end;
    if c is TCheckBox then
    begin
      TCheckBox(c).IsChecked := db.ReadSetting(TCheckBox(c).Name, '0') = '1';
    end;
  end;
  ColorStr := db.ReadSetting('cpStyleBlockColor', 'FF000000');
  if TryStrToUInt('$' + ColorStr, Cardinal(SavedColor)) then
    frChatOBS1.cpStyleBlockColor.Color := SavedColor
  else
    frChatOBS1.cpStyleBlockColor.Color := TAlphaColorRec.Black;

  if not DirectoryExists(myConst.fontsPath) then
    CreateDirectory(PChar(myConst.fontsPath), 0);
  var
  n := 1;
  var
  cDir := myConst.fontsPath; // Искать в папке с программой
  var
  FileName := '*.*'; // Ищем все файлы
  ChDir(cDir); // войти в каталог
  var
    SearchRec: TSearchRec;
  if FindFirst(FileName, faArchive, SearchRec) = 0 then
    repeat
      if (SearchRec.Attr and faAnyFile) = SearchRec.Attr then
      begin
        frChatOBS1.cbFontStyleDefault.Items.Add(SearchRec.Name);
        Inc(n);
      end;
    until FindNext(SearchRec) <> 0;
  ChDir('..');

  for I := 0 to frNotify1.ComponentCount - 1 do
  begin
    c := frNotify1.components[I];
    if c is TEdit then
    begin
      TEdit(c).text := db.ReadSetting(TEdit(c).Name);
    end;
    if c is TCheckBox then
    begin
      TCheckBox(c).IsChecked := (db.ReadSetting(TCheckBox(c).Name) = 'True');
    end;
    if c is TSwitch then
    begin
      TSwitch(c).IsChecked := (db.ReadSetting(TSwitch(c).Name) = 'True');
    end;
    if c is TTrackBar then
    begin
      TTrackBar(c).Value := strtoint(db.ReadSetting(TTrackBar(c).Name, '100'));
    end;
  end;
  var
    ii: Integer;
  for I := 0 to frAI1.ComponentCount - 1 do
  begin
    c := frAI1.components[I];
    if c is TEdit then
    begin
      TEdit(c).text := db.ReadSetting(TEdit(c).Name);
    end;
    if c is TCheckBox then
    begin
      TCheckBox(c).IsChecked := db.ReadSetting(TCheckBox(c).Name) = '1';
    end;

  end;
  ii := strtoint(db.ReadSetting('aiIndex', '0'));

  case ii of
    0:
      begin
        frAI1.rbGC.IsChecked := True;
        frAI1.Label45.text := 'ClientID';
        frAI1.Label47.text := 'Autorization Code';
        frAI1.Label1.Visible := false;
        frAI1.edtAIP2.Visible := True;
        frAI1.edtAIP2.Password := True;
        frAI1.edtAIP3.Visible := false;
        frAI1.cbOllama.IsChecked := false;
        frAI1.cbOllama.Visible := false;
      end;
    1:
      begin
        frAI1.rbDS.IsChecked := True;
        frAI1.Label45.text := 'API Token';
        frAI1.Label47.text := '';
        frAI1.Label1.Visible := false;
        frAI1.edtAIP2.Visible := false;
        frAI1.edtAIP2.Password := false;
        frAI1.edtAIP3.Visible := false;
        frAI1.cbOllama.IsChecked := false;
        frAI1.cbOllama.Visible := false;
      end;
    2:
      begin
        frAI1.rbCG.IsChecked := True;
        frAI1.Label45.text := 'API Token';
        frAI1.Label47.text := '';
        frAI1.Label1.Visible := false;
        frAI1.edtAIP2.Visible := false;
        frAI1.edtAIP2.Password := false;
        frAI1.edtAIP3.Visible := false;
        frAI1.cbOllama.IsChecked := false;
        frAI1.cbOllama.Visible := false;
      end;
    3:
      begin
        frAI1.RBCustom.IsChecked := True;
        frAI1.Label45.text := 'API Token';
        frAI1.Label47.text := 'URL';
        frAI1.Label1.Visible := True;
        frAI1.edtAIP2.Visible := True;
        frAI1.edtAIP2.Password := false;
        frAI1.edtAIP3.Visible := True;
        frAI1.cbOllama.IsChecked := db.ReadSetting(frAI1.cbOllama.Name) = '1';
        frAI1.cbOllama.Visible := True;
      end;
  end;

  db.LoadGridFromTable('sgTimers', frAutoActions1.sgTimers);
  db.LoadGridFromTable('sgCounter', frAutoActions1.sgCounter);
  db.LoadGridFromTable('sgBanWords', frAutoActions1.sgBanWords);

end;

end.
