unit frm_PlantaConfig;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf,
  FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Phys, FireDAC.Phys.MySQL,
  FireDAC.Phys.MySQLDef, FireDAC.Comp.Client,
  uScaleConfig, dm_LocalData;

type
  TfrmPlantaConfig = class(TForm)
    pnlHeader: TPanel;
    lblTitle: TLabel;
    pnlContent: TPanel;
    grpBascula: TGroupBox;
    lblPuerto: TLabel;
    cbbPuerto: TComboBox;
    lblBaudRate: TLabel;
    cbbBaudRate: TComboBox;
    chkSimulado: TCheckBox;
    lblTolerancia: TLabel;
    edtTolerancia: TEdit;
    grpObrador: TGroupBox;
    lblEmpresa: TLabel;
    lblObrador: TLabel;
    cbbEmpresa: TComboBox;
    btnCargarServidor: TButton;
    cbbObrador: TComboBox;
    grpServidor: TGroupBox;
    lblHost: TLabel;
    edtHost: TEdit;
    lblPuertoServ: TLabel;
    edtPuertoServ: TEdit;
    lblDb: TLabel;
    edtDb: TEdit;
    lblUser: TLabel;
    edtUser: TEdit;
    lblPass: TLabel;
    edtPass: TEdit;
    pnlFooter: TPanel;
    btnGuardar: TButton;
    btnCancelar: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnGuardarClick(Sender: TObject);
    procedure btnCancelarClick(Sender: TObject);
    procedure cbbEmpresaChange(Sender: TObject);
    procedure btnCargarServidorClick(Sender: TObject);
  private
    FConfig: TScaleConfig;
    procedure LoadConfigToUI;
    procedure SaveUIToConfig;
    procedure LoadEmpresasFromLocal;
    procedure LoadObradoresFromLocal(AEmpresaId: Integer);
    procedure FetchCatalogosFromServer(ASilent: Boolean);
  public
    class function Execute(var AConfig: TScaleConfig): Boolean;
  end;

implementation

{$R *.dfm}

class function TfrmPlantaConfig.Execute(var AConfig: TScaleConfig): Boolean;
var
  LFrm: TfrmPlantaConfig;
begin
  LFrm := TfrmPlantaConfig.Create(Application);
  try
    LFrm.FConfig := AConfig;
    LFrm.LoadConfigToUI;
    Result := (LFrm.ShowModal = mrOk);
    if Result then
      AConfig := LFrm.FConfig;
  finally
    LFrm.Free;
  end;
end;

procedure TfrmPlantaConfig.FormCreate(Sender: TObject);
begin
  Tag := 999;
end;

procedure TfrmPlantaConfig.LoadEmpresasFromLocal;
var
  LQry: TFDQuery;
  LIdx: Integer;
  LId: Integer;
begin
  cbbEmpresa.Items.BeginUpdate;
  try
    cbbEmpresa.Items.Clear;
    try
      LQry := dmLocalData.OpenLocalQuery('SELECT id_servidor, nombre FROM local_empresas ORDER BY nombre');
      try
        while not LQry.Eof do
        begin
          LId := LQry.FieldByName('id_servidor').AsInteger;
          cbbEmpresa.Items.AddObject(
            LQry.FieldByName('nombre').AsString,
            TObject(IntPtr(LId))
          );
          LQry.Next;
        end;
      finally
        LQry.Free;
      end;
    except
      // Si la tabla no está creada aún o falla, continuar limpiamente
    end;
  finally
    cbbEmpresa.Items.EndUpdate;
  end;

  if cbbEmpresa.Items.Count > 0 then
  begin
    cbbEmpresa.ItemIndex := 0;
    for LIdx := 0 to cbbEmpresa.Items.Count - 1 do
    begin
      if Integer(IntPtr(cbbEmpresa.Items.Objects[LIdx])) = FConfig.DefaultEmpresaId then
      begin
        cbbEmpresa.ItemIndex := LIdx;
        Break;
      end;
    end;
  end;
end;

procedure TfrmPlantaConfig.LoadObradoresFromLocal(AEmpresaId: Integer);
var
  LQry: TFDQuery;
  LIdx: Integer;
  LId: Integer;
begin
  cbbObrador.Items.BeginUpdate;
  try
    cbbObrador.Items.Clear;
    try
      if AEmpresaId > 0 then
        LQry := dmLocalData.OpenLocalQuery(
          'SELECT id_servidor, nombre FROM local_obradores WHERE id_empresa = ? ORDER BY nombre',
          [AEmpresaId]
        )
      else
        LQry := dmLocalData.OpenLocalQuery(
          'SELECT id_servidor, nombre FROM local_obradores ORDER BY nombre'
        );

      try
        while not LQry.Eof do
        begin
          LId := LQry.FieldByName('id_servidor').AsInteger;
          cbbObrador.Items.AddObject(
            LQry.FieldByName('nombre').AsString,
            TObject(IntPtr(LId))
          );
          LQry.Next;
        end;
      finally
        LQry.Free;
      end;
    except
      // Si la tabla no está creada aún o falla, continuar limpiamente
    end;
  finally
    cbbObrador.Items.EndUpdate;
  end;

  if cbbObrador.Items.Count > 0 then
  begin
    cbbObrador.ItemIndex := 0;
    for LIdx := 0 to cbbObrador.Items.Count - 1 do
    begin
      if Integer(IntPtr(cbbObrador.Items.Objects[LIdx])) = FConfig.DefaultObradorId then
      begin
        cbbObrador.ItemIndex := LIdx;
        Break;
      end;
    end;
  end;
end;

procedure TfrmPlantaConfig.FetchCatalogosFromServer(ASilent: Boolean);
var
  LConn: TFDConnection;
  LDriver: TFDPhysMySQLDriverLink;
  LQry: TFDQuery;
  LCountEmp, LCountObr: Integer;
begin
  LConn := TFDConnection.Create(nil);
  LDriver := TFDPhysMySQLDriverLink.Create(nil);
  try
    try
      LConn.LoginPrompt := False;
      LConn.Params.Clear;
      LConn.Params.DriverID := 'MySQL';
      LConn.Params.Add('Server=' + edtHost.Text);
      LConn.Params.Add('Port=' + edtPuertoServ.Text);
      LConn.Params.Add('Database=' + edtDb.Text);
      LConn.Params.Add('User_Name=' + edtUser.Text);
      LConn.Params.Add('Password=' + edtPass.Text);
      LConn.Params.Add('CharacterSet=utf8mb4');
      LConn.Params.Add('ReadTimeout=4000');
      LConn.Connected := True;

      LQry := TFDQuery.Create(nil);
      try
        LQry.Connection := LConn;

        // 1. Descargar Empresas
        LQry.SQL.Text := 'SELECT id, nombre FROM ge_empresas WHERE activo = 1 ORDER BY nombre';
        LQry.Open;
        dmLocalData.localConn.StartTransaction;
        try
          LCountEmp := 0;
          while not LQry.Eof do
          begin
            dmLocalData.ExecLocalSQL(
              'INSERT OR REPLACE INTO local_empresas (id_servidor, nombre) VALUES (?, ?)',
              [LQry.FieldByName('id').AsInteger, LQry.FieldByName('nombre').AsString]
            );
            Inc(LCountEmp);
            LQry.Next;
          end;
          dmLocalData.localConn.Commit;
        except
          dmLocalData.localConn.Rollback;
          raise;
        end;
        LQry.Close;

        // 2. Descargar Obradores
        LQry.SQL.Text := 'SELECT id, id_empresa, nombre FROM ge_obradores WHERE activo = 1 ORDER BY nombre';
        LQry.Open;
        dmLocalData.localConn.StartTransaction;
        try
          LCountObr := 0;
          while not LQry.Eof do
          begin
            dmLocalData.ExecLocalSQL(
              'INSERT OR REPLACE INTO local_obradores (id_servidor, id_empresa, nombre) VALUES (?, ?, ?)',
              [LQry.FieldByName('id').AsInteger, LQry.FieldByName('id_empresa').AsInteger,
               LQry.FieldByName('nombre').AsString]
            );
            Inc(LCountObr);
            LQry.Next;
          end;
          dmLocalData.localConn.Commit;
        except
          dmLocalData.localConn.Rollback;
          raise;
        end;
        LQry.Close;

      finally
        LQry.Free;
      end;

      if not ASilent then
        ShowMessage(Format('Catálogos actualizados con éxito desde el servidor:' + sLineBreak +
                           '• %d Empresa(s)' + sLineBreak +
                           '• %d Obrador(es)', [LCountEmp, LCountObr]));
    except
      on E: Exception do
      begin
        if not ASilent then
          ShowMessage('No se pudo conectar con el servidor MariaDB:' + sLineBreak + E.Message);
      end;
    end;
  finally
    LConn.Free;
    LDriver.Free;
  end;
end;

procedure TfrmPlantaConfig.cbbEmpresaChange(Sender: TObject);
var
  LEmpresaId: Integer;
begin
  if cbbEmpresa.ItemIndex >= 0 then
    LEmpresaId := Integer(IntPtr(cbbEmpresa.Items.Objects[cbbEmpresa.ItemIndex]))
  else
    LEmpresaId := 0;

  LoadObradoresFromLocal(LEmpresaId);
end;

procedure TfrmPlantaConfig.btnCargarServidorClick(Sender: TObject);
var
  LEmpresaId: Integer;
begin
  FetchCatalogosFromServer(False);
  LoadEmpresasFromLocal;
  if cbbEmpresa.ItemIndex >= 0 then
    LEmpresaId := Integer(IntPtr(cbbEmpresa.Items.Objects[cbbEmpresa.ItemIndex]))
  else
    LEmpresaId := 0;
  LoadObradoresFromLocal(LEmpresaId);
end;

procedure TfrmPlantaConfig.LoadConfigToUI;
var
  LEmpresaId: Integer;
begin
  cbbPuerto.Text := FConfig.PortName;
  cbbBaudRate.Text := IntToStr(FConfig.BaudRate);
  chkSimulado.Checked := FConfig.Simulated;
  edtTolerancia.Text := FloatToStr(FConfig.ToleranceGrams);

  edtHost.Text := FConfig.ServerHost;
  edtPuertoServ.Text := IntToStr(FConfig.ServerPort);
  edtDb.Text := FConfig.ServerDatabase;
  edtUser.Text := FConfig.ServerUser;
  edtPass.Text := FConfig.ServerPass;

  // Cargar empresas locales
  LoadEmpresasFromLocal;

  // Si no hay datos locales, intentar descargarlos del servidor si está accesible
  if cbbEmpresa.Items.Count = 0 then
  begin
    FetchCatalogosFromServer(True);
    LoadEmpresasFromLocal;
  end;

  if cbbEmpresa.ItemIndex >= 0 then
    LEmpresaId := Integer(IntPtr(cbbEmpresa.Items.Objects[cbbEmpresa.ItemIndex]))
  else
    LEmpresaId := FConfig.DefaultEmpresaId;

  LoadObradoresFromLocal(LEmpresaId);
end;

procedure TfrmPlantaConfig.SaveUIToConfig;
begin
  FConfig.PortName := cbbPuerto.Text;
  FConfig.BaudRate := StrToIntDef(cbbBaudRate.Text, 9600);
  FConfig.Simulated := chkSimulado.Checked;
  FConfig.ToleranceGrams := StrToFloatDef(StringReplace(edtTolerancia.Text, ',', '.', [rfReplaceAll]), 2.0);

  if cbbEmpresa.ItemIndex >= 0 then
    FConfig.DefaultEmpresaId := Integer(IntPtr(cbbEmpresa.Items.Objects[cbbEmpresa.ItemIndex]))
  else
    FConfig.DefaultEmpresaId := 1;

  if cbbObrador.ItemIndex >= 0 then
    FConfig.DefaultObradorId := Integer(IntPtr(cbbObrador.Items.Objects[cbbObrador.ItemIndex]))
  else
    FConfig.DefaultObradorId := 1;

  FConfig.ServerHost := edtHost.Text;
  FConfig.ServerPort := StrToIntDef(edtPuertoServ.Text, 3306);
  FConfig.ServerDatabase := edtDb.Text;
  FConfig.ServerUser := edtUser.Text;
  FConfig.ServerPass := edtPass.Text;

  FConfig.SaveToIni;
end;

procedure TfrmPlantaConfig.btnGuardarClick(Sender: TObject);
begin
  SaveUIToConfig;
  ModalResult := mrOk;
end;

procedure TfrmPlantaConfig.btnCancelarClick(Sender: TObject);
begin
  ModalResult := mrCancel;
end;

end.
