unit frm_FamiliasEditor;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Buttons,
  Vcl.ComCtrls, Data.DB, FireDAC.Comp.Client, uAppTheme, FireDAC.Stan.Param, uBaseForm,
  Vcl.Grids, Vcl.DBGrids;

type
  TfrmFamiliasEditor = class(TfrmBase)
    lblCodigo: TLabel;
    edtCodigo: TEdit;
    lblDescripcion: TLabel;
    edtDescripcion: TEdit;
    procedure FormShow(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnSalirClick(Sender: TObject);
    procedure btnEliminarClick(Sender: TObject);
  protected
    procedure DoAnadir; override;
    procedure DoModificar; override;
    procedure DoPrimero; override;
    procedure DoAnterior; override;
    procedure DoSiguiente; override;
    procedure DoUltimo; override;
  private
    FFamiliaId: string;
    FParentForm: TForm;
    dsArticulos: TDataSource;
    qryArticulos: TFDQuery;
    chkActivo: TCheckBox;
    procedure LoadData;
    procedure LoadArticulos;
  public
    property FamiliaId: string read FFamiliaId write FFamiliaId;
    property ParentForm: TForm read FParentForm write FParentForm;
  end;

var
  frmFamiliasEditor: TfrmFamiliasEditor;

implementation

uses
  dmg_Main, uDbErrorHandler, frm_Familias;

{$R *.dfm}

procedure TfrmFamiliasEditor.FormShow(Sender: TObject);
begin
  // Aplicar tema estándar
  TAppTheme.ApplyToForm(Self);

  // Vincular eventos a la barra superior heredada
  btnGuardar.OnClick := btnSaveClick;
  btnSalir.OnClick := btnSalirClick;
  btnEliminar.OnClick := btnEliminarClick;

  // Ocultar componentes/paneles heredados innecesarios para mantenimiento simple
  pgcDetails.Visible := True;
  TsListado.TabVisible := False;
  pgcDetails.ActivePage := tsDatosEnvio;
  pnlSideToolbar.Visible := False;
  dbgItems.Visible := True;
  pnlFooter.Visible := False;

  // Configurar componentes de código como ID (lectura únicamente)
  lblCodigo.Caption := 'ID:';
  lblCodigo.Visible := True;
  edtCodigo.Visible := True;
  edtCodigo.ReadOnly := True;
  edtCodigo.Color := clBtnFace;

  // Crear dinámicamente chkActivo
  if not Assigned(chkActivo) then
  begin
    chkActivo := TCheckBox.Create(Self);
    chkActivo.Parent := edtDescripcion.Parent;
    chkActivo.Left := edtDescripcion.Left;
    chkActivo.Top := edtDescripcion.Top + edtDescripcion.Height + 15;
    chkActivo.Width := 150;
    chkActivo.Caption := 'Familia Activa';
  end;

  // Inicializar componentes dinámicos de artículos
  if not Assigned(dsArticulos) then
  begin
    qryArticulos := TFDQuery.Create(Self);
    qryArticulos.Connection := dmgMain.dbConn;
    
    dsArticulos := TDataSource.Create(Self);
    dsArticulos.DataSet := qryArticulos;
    
    dbgItems.DataSource := dsArticulos;
  end;

  // Configurar rejilla de artículos y materias primas
  dbgItems.Columns.Clear;
  with dbgItems.Columns.Add do
  begin
    FieldName := 'tipo';
    Title.Caption := 'Tipo';
    Width := 100;
    ReadOnly := True;
  end;

  with dbgItems.Columns.Add do
  begin
    FieldName := 'descripcion';
    Title.Caption := 'Descripción';
    Width := 350;
    ReadOnly := True;
  end;
  with dbgItems.Columns.Add do
  begin
    FieldName := 'pvp1';
    Title.Caption := 'Precio';
    Width := 100;
    Alignment := taRightJustify;
    ReadOnly := True;
  end;
  with dbgItems.Columns.Add do
  begin
    FieldName := 'activo';
    Title.Caption := 'Activo';
    Width := 80;
    ReadOnly := True;
  end;

  // Cargar datos
  if FFamiliaId <> '' then
    LoadData
  else
  begin
    edtDescripcion.Clear;
    if Assigned(qryArticulos) then
      qryArticulos.Close;
  end;
end;

procedure TfrmFamiliasEditor.LoadData;
begin
  dmgMain.qryExec.Close;
  dmgMain.qryExec.SQL.Text := 'SELECT id, descripcion, activo FROM ge_familias WHERE id = :id';
  dmgMain.qryExec.ParamByName('id').AsString := FFamiliaId;
  dmgMain.qryExec.Open;
  
  if not dmgMain.qryExec.IsEmpty then
  begin
    edtCodigo.Text := dmgMain.qryExec.FieldByName('id').AsString;
    edtDescripcion.Text := dmgMain.qryExec.FieldByName('descripcion').AsString;
    if Assigned(chkActivo) then
      chkActivo.Checked := dmgMain.qryExec.FieldByName('activo').AsInteger <> 0;
  end;
  dmgMain.qryExec.Close;

  LoadArticulos;
end;

procedure TfrmFamiliasEditor.LoadArticulos;
begin
  if not Assigned(qryArticulos) then Exit;
  
  qryArticulos.Close;
  qryArticulos.SQL.Text :=
    'SELECT CONVERT(id USING utf8mb4) COLLATE utf8mb4_general_ci AS id, ' +
    '       CONVERT(descripcion USING utf8mb4) COLLATE utf8mb4_general_ci AS descripcion, ' +
    '       pvp1, activo, ' +
    '       CONVERT(''Artículo'' USING utf8mb4) COLLATE utf8mb4_general_ci AS tipo ' +
    'FROM ge_articulos ' +
    'WHERE id_familia = :id_familia ' +
    'UNION ALL ' +
    'SELECT CONVERT(id USING utf8mb4) COLLATE utf8mb4_general_ci AS id, ' +
    '       CONVERT(descripcion USING utf8mb4) COLLATE utf8mb4_general_ci AS descripcion, ' +
    '       CAST(0.0000 AS DECIMAL(15,4)) AS pvp1, activo, ' +
    '       CONVERT(''Materia Prima'' USING utf8mb4) COLLATE utf8mb4_general_ci AS tipo ' +
    'FROM ge_materias_primas ' +
    'WHERE familia_id = :id_familia ' +
    'ORDER BY descripcion';
  qryArticulos.ParamByName('id_familia').AsString := FFamiliaId;
  qryArticulos.Open;
end;

procedure TfrmFamiliasEditor.btnSaveClick(Sender: TObject);
var
  LIsNew: Boolean;
begin
  if Trim(edtDescripcion.Text) = '' then
  begin
    ShowMessage('La descripción de la familia es obligatoria.');
    Exit;
  end;

  LIsNew := (FFamiliaId = '');

  dmgMain.qryExec.Close;
  if LIsNew then
  begin
    dmgMain.qryExec.SQL.Text :=
      'INSERT INTO ge_familias (descripcion, activo, id_user_creator, id_user_update) ' +
      'VALUES (:desc, :act, :user, :user)';
  end
  else
  begin
    dmgMain.qryExec.SQL.Text :=
      'UPDATE ge_familias SET descripcion = :desc, activo = :act, id_user_update = :user, updated_at = CURRENT_TIMESTAMP ' +
      'WHERE id = :id';
    dmgMain.qryExec.ParamByName('id').AsString := FFamiliaId;
  end;

  dmgMain.qryExec.ParamByName('desc').AsString := edtDescripcion.Text;
  if Assigned(chkActivo) and chkActivo.Checked then
    dmgMain.qryExec.ParamByName('act').AsInteger := 1
  else
    dmgMain.qryExec.ParamByName('act').AsInteger := 0;
  dmgMain.qryExec.ParamByName('user').AsString := dmgMain.CurrentUserId;

  try
    dmgMain.qryExec.ExecSQL;
    
    if LIsNew then
    begin
      dmgMain.qryExec.Close;
      dmgMain.qryExec.SQL.Text := 'SELECT LAST_INSERT_ID()';
      dmgMain.qryExec.Open;
      FFamiliaId := dmgMain.qryExec.Fields[0].AsString;
      dmgMain.qryExec.Close;
    end;
    
    ResetChangeTracking;
    if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
      TfrmFamilias(FParentForm).btnRefreshClick(nil);
    ShowMessage('Familia guardada correctamente.');
  except
    on E: Exception do
      TDbErrorHandler.HandleException(E, dmgMain.qryExec.SQL.Text);
  end;
end;

procedure TfrmFamiliasEditor.btnSalirClick(Sender: TObject);
begin
  ModalResult := mrCancel;
  Close;
end;

procedure TfrmFamiliasEditor.DoAnadir;
begin
  FFamiliaId := '';
  edtCodigo.Text := 'AUTO';
  edtDescripcion.Clear;
  if Assigned(chkActivo) then
    chkActivo.Checked := True;
  if Assigned(qryArticulos) then
    qryArticulos.Close;
  edtDescripcion.SetFocus;
end;

procedure TfrmFamiliasEditor.DoModificar;
begin
  edtDescripcion.SetFocus;
end;

procedure TfrmFamiliasEditor.DoPrimero;
var
  LParent: TfrmFamilias;
begin
  LParent := nil;
  if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
    LParent := TfrmFamilias(FParentForm)
  else if Assigned(frmFamilias) then
    LParent := frmFamilias;

  if Assigned(LParent) and Assigned(LParent.QryMain) and not LParent.QryMain.IsEmpty then
  begin
    LParent.QryMain.First;
    FFamiliaId := LParent.QryMain.FieldByName('id').AsString;
    LoadData;
  end;
end;

procedure TfrmFamiliasEditor.DoAnterior;
var
  LParent: TfrmFamilias;
begin
  LParent := nil;
  if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
    LParent := TfrmFamilias(FParentForm)
  else if Assigned(frmFamilias) then
    LParent := frmFamilias;

  if Assigned(LParent) and Assigned(LParent.QryMain) and not LParent.QryMain.IsEmpty then
  begin
    LParent.QryMain.Prior;
    FFamiliaId := LParent.QryMain.FieldByName('id').AsString;
    LoadData;
  end;
end;

procedure TfrmFamiliasEditor.DoSiguiente;
var
  LParent: TfrmFamilias;
begin
  LParent := nil;
  if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
    LParent := TfrmFamilias(FParentForm)
  else if Assigned(frmFamilias) then
    LParent := frmFamilias;

  if Assigned(LParent) and Assigned(LParent.QryMain) and not LParent.QryMain.IsEmpty then
  begin
    LParent.QryMain.Next;
    FFamiliaId := LParent.QryMain.FieldByName('id').AsString;
    LoadData;
  end;
end;

procedure TfrmFamiliasEditor.DoUltimo;
var
  LParent: TfrmFamilias;
begin
  LParent := nil;
  if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
    LParent := TfrmFamilias(FParentForm)
  else if Assigned(frmFamilias) then
    LParent := frmFamilias;

  if Assigned(LParent) and Assigned(LParent.QryMain) and not LParent.QryMain.IsEmpty then
  begin
    LParent.QryMain.Last;
    FFamiliaId := LParent.QryMain.FieldByName('id').AsString;
    LoadData;
  end;
end;

procedure TfrmFamiliasEditor.btnEliminarClick(Sender: TObject);
var
  LNextId: string;
  LParent: TfrmFamilias;
begin
  if FFamiliaId = '' then
  begin
    ShowMessage('No hay ningún registro guardado para eliminar.');
    Exit;
  end;

  if MessageDlg('¿Está seguro de que desea eliminar esta familia?' + #13#10#13#10 +
                'ATENCIÓN: Todos los artículos asociados quedarán sin familia y se les deberá asignar una nueva familia de forma manual.', 
                mtWarning, [mbYes, mbNo], 0) = mrYes then
  begin
    LNextId := '';
    LParent := nil;
    if Assigned(FParentForm) and (FParentForm is TfrmFamilias) then
      LParent := TfrmFamilias(FParentForm)
    else if Assigned(frmFamilias) then
      LParent := frmFamilias;

    if Assigned(LParent) and Assigned(LParent.QryMain) then
    begin
      LParent.QryMain.Next;
      if not LParent.QryMain.Eof then
      begin
        LNextId := LParent.QryMain.FieldByName('id').AsString;
        LParent.QryMain.Prior;
      end
      else
      begin
        LParent.QryMain.Prior;
        LParent.QryMain.Prior;
        if not LParent.QryMain.Bof then
        begin
          LNextId := LParent.QryMain.FieldByName('id').AsString;
          LParent.QryMain.Next;
        end
        else
        begin
          LParent.QryMain.Next;
        end;
      end;
    end;

    try
      // Desasociar artículos de esta familia primero
      dmgMain.qryExec.Close;
      dmgMain.qryExec.SQL.Text := 'UPDATE ge_articulos SET id_familia = NULL WHERE id_familia = :id';
      dmgMain.qryExec.ParamByName('id').AsString := FFamiliaId;
      dmgMain.qryExec.ExecSQL;

      // Eliminar familia
      dmgMain.qryExec.Close;
      dmgMain.qryExec.SQL.Text := 'DELETE FROM ge_familias WHERE id = :id';
      dmgMain.qryExec.ParamByName('id').AsString := FFamiliaId;
      dmgMain.qryExec.ExecSQL;

      if Assigned(LParent) then
      begin
        LParent.btnRefreshClick(nil);
        if LNextId <> '' then
        begin
          LParent.QryMain.Locate('id', LNextId, []);
          FFamiliaId := LNextId;
          LoadData;
        end;
      end;

      if LNextId = '' then
      begin
        ShowMessage('Se ha eliminado el único registro disponible.');
        ModalResult := mrOk;
      end;
    except
      on E: Exception do
        ShowMessage('Error al eliminar la familia: ' + E.Message);
    end;
  end;
end;

end.
