unit frm_StockEnvasado;

interface

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

type
  TfrmStockEnvasado = class(TfrmBaseList)
    rbStockPositivo: TRadioButton;
    rbStockTodos: TRadioButton;
    btnInventario: TSpeedButton;

    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnRefreshClick(Sender: TObject); override;
    procedure btnNewClick(Sender: TObject); override;
    procedure btnEditClick(Sender: TObject); override;
    procedure btnDeleteClick(Sender: TObject); override;
    procedure btnPrintClick(Sender: TObject); override;
    procedure rbStockFilterClick(Sender: TObject);
    procedure btnInventarioClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmStockEnvasado: TfrmStockEnvasado;

implementation

uses
  dmg_Main, uDbErrorHandler, frm_StockEnvasadoEditor, frm_PrintEtiquetasStock, frm_InventarioStockEnvasado;

{$R *.dfm}

procedure TfrmStockEnvasado.FormShow(Sender: TObject);
begin
  inherited;
  frmStockEnvasado := Self;
  OnDestroy := FormDestroy;
  
  // Activar zona lateral de filtros (heredada de TfrmBaseList)
  pnlLeftFilter.Visible := True;
  grpStatuses.Visible := True;
  grpStatuses.Caption := 'Filtro por Stock';
  grpDates.Visible := True;

  pnlSearch.Visible := True;
  lblSearch.Caption := 'Buscar Producto/Lote:';
  
  btnNuevo.Visible := True;
  btnEditar.Visible := True;
  btnBorrar.Visible := True;

  btnPrint.Width := 55;
  btnPrint.Visible := True;
  btnPrint.Caption := 'Etiquetas';
  btnPrint.Hint := 'Imprimir etiquetas de producto o envasado (DUN-14)';
end;

procedure TfrmStockEnvasado.FormDestroy(Sender: TObject);
begin
  if frmStockEnvasado = Self then
    frmStockEnvasado := nil;
end;

procedure TfrmStockEnvasado.rbStockFilterClick(Sender: TObject);
begin
  btnRefreshClick(nil);
end;

procedure TfrmStockEnvasado.btnRefreshClick(Sender: TObject);
var
  LSql: string;
begin
  FQryMain.Close;
  LSql := 'SELECT se.id, alm.descripcion as almacen_desc, e.nombre as empresa_almacen, ' +
          'CONCAT(art.id, '' - '', art.descripcion) as articulo_desc, art.activo as articulo_activo, ' +
          'COALESCE(NULLIF(l.codigo_antiguo, ''''), l.codigo) as lote_codigo, l.fecha as fecha_elaboracion, ' +
          '(CASE WHEN l.fecha IS NOT NULL AND art.dias_vida > 0 THEN DATE_ADD(l.fecha, INTERVAL art.dias_vida DAY) ELSE NULL END) as fecha_caducidad, ' +
          'fp.descripcion as formato_desc, COALESCE(se.cantidad_producida, 0) as cantidad_producida, se.cantidad_unidades, ' +
          'COALESCE(se.cantidad_reservada, 0) as cantidad_reservada, ' +
          'GREATEST(0, se.cantidad_unidades - COALESCE(se.cantidad_reservada, 0)) as stock_disponible ' +
          'FROM ge_stock_envasado se ' +
          'JOIN ge_almacenes alm ON se.id_almacen = alm.id ' +
          'LEFT JOIN ge_empresas e ON alm.id_empresa = e.id ' +
          'JOIN ge_articulos art ON se.id_articulo = art.id ' +
          'JOIN ge_lotes l ON se.id_lote = l.id ' +
          'JOIN ge_formatos_presentacion fp ON se.id_formato_presentacion = fp.id ' +
          'WHERE (alm.id_empresa = :emp OR alm.compartido = 1) ';
          
  // Filtro por defecto: Stock > 0
  if not Assigned(rbStockTodos) or (Assigned(rbStockPositivo) and rbStockPositivo.Checked) then
    LSql := LSql + 'AND se.cantidad_unidades > 0 ';

  // Filtro por Fechas (Fechas de ingreso)
  if Assigned(rbDateToday) and rbDateToday.Checked then
    LSql := LSql + 'AND se.created_at >= ' + QuotedStr(FormatDateTime('yyyy-mm-dd 00:00:00', Date)) + ' '
  else if Assigned(rbDateWeek) and rbDateWeek.Checked then
    LSql := LSql + 'AND se.created_at >= ' + QuotedStr(FormatDateTime('yyyy-mm-dd 00:00:00', Date - 7)) + ' '
  else if Assigned(rbDateMonth) and rbDateMonth.Checked then
    LSql := LSql + 'AND se.created_at >= ' + QuotedStr(FormatDateTime('yyyy-mm-dd 00:00:00', IncMonth(Date, -1))) + ' '
  else if Assigned(rbDateCustom) and rbDateCustom.Checked then
    LSql := LSql + 'AND (se.created_at >= ' + QuotedStr(FormatDateTime('yyyy-mm-dd 00:00:00', dtpStart.Date)) +
                   ' AND se.created_at <= ' + QuotedStr(FormatDateTime('yyyy-mm-dd 23:59:59', dtpEnd.Date)) + ') ';

  // Filtro por texto de búsqueda
  if Trim(edtSearch.Text) <> '' then
  begin
    LSql := LSql + 'AND (art.descripcion LIKE :search OR CAST(l.codigo AS CHAR) LIKE :search OR CAST(COALESCE(l.codigo_antiguo, '''') AS CHAR) LIKE :search OR alm.descripcion LIKE :search) ';
  end;

  // Ordenación por defecto por Lote (código del lote descendentemente)
  LSql := LSql + 'ORDER BY COALESCE(NULLIF(l.codigo_antiguo, ''''), l.codigo) DESC, se.created_at DESC';
  
  FQryMain.SQL.Text := LSql;
  FQryMain.ParamByName('emp').AsString := dmgMain.CurrentCompanyId;
  
  if Trim(edtSearch.Text) <> '' then
  begin
    FQryMain.ParamByName('search').DataType := ftWideString;
    FQryMain.ParamByName('search').AsWideString := '%' + Trim(edtSearch.Text) + '%';
  end;
    
  FQryMain.Open;
  
  lblRecordCount.Caption := Format('Registros: %d', [FQryMain.RecordCount]);

  dbGridMain.Columns.Clear;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'id';
    Title.Caption := 'ID';
    Width := 50;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'lote_codigo';
    Title.Caption := 'Lote';
    Width := 100;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'fecha_elaboracion';
    Title.Caption := 'Fecha Elaboración';
    Width := 110;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'fecha_caducidad';
    Title.Caption := 'Fecha Caducidad';
    Width := 110;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'articulo_desc';
    Title.Caption := 'Producto / Artículo';
    Width := 250;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'cantidad_producida';
    Title.Caption := 'Cant. Fabricada';
    Width := 105;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'cantidad_unidades';
    Title.Caption := 'Stock (Uds.)';
    Width := 90;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'cantidad_reservada';
    Title.Caption := 'Uds. Reservadas';
    Width := 100;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'stock_disponible';
    Title.Caption := 'Stock Disponible';
    Width := 100;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'formato_desc';
    Title.Caption := 'Presentación';
    Width := 130;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'almacen_desc';
    Title.Caption := 'Almacén';
    Width := 180;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'empresa_almacen';
    Title.Caption := 'Empresa Almacén';
    Width := 160;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'articulo_activo';
    Title.Caption := 'Art. Activo';
    Width := 75;
  end;
end;

procedure TfrmStockEnvasado.btnNewClick(Sender: TObject);
var
  LEditor: TfrmStockEnvasadoEditor;
begin
  LEditor := TfrmStockEnvasadoEditor.Create(Self);
  try
    LEditor.StockId := 0;
    LEditor.ParentForm := Self;
    if LEditor.ShowModal = mrOk then
      btnRefreshClick(nil);
  finally
    LEditor.Free;
  end;
end;

procedure TfrmStockEnvasado.btnEditClick(Sender: TObject);
var
  LEditor: TfrmStockEnvasadoEditor;
begin
  if FQryMain.IsEmpty then Exit;
  
  LEditor := TfrmStockEnvasadoEditor.Create(Self);
  try
    LEditor.StockId := FQryMain.FieldByName('id').AsInteger;
    LEditor.ParentForm := Self;
    if LEditor.ShowModal = mrOk then
      btnRefreshClick(nil);
  finally
    LEditor.Free;
  end;
end;

procedure TfrmStockEnvasado.btnDeleteClick(Sender: TObject);
var
  LId: Integer;
begin
  if FQryMain.IsEmpty then Exit;
  
  if MessageDlg('¿Confirma que desea eliminar esta entrada de stock?', mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
    Exit;
    
  LId := FQryMain.FieldByName('id').AsInteger;
  try
    dmgMain.qryExec.Close;
    dmgMain.qryExec.SQL.Text := 'DELETE FROM ge_stock_envasado WHERE id = :id';
    dmgMain.qryExec.ParamByName('id').AsInteger := LId;
    dmgMain.qryExec.ExecSQL;
    
    btnRefreshClick(nil);
  except
    on E: Exception do
      TDbErrorHandler.HandleException(E, 'Error al eliminar entrada de stock');
  end;
end;

procedure TfrmStockEnvasado.btnPrintClick(Sender: TObject);
var
  LPrintDlg: TfrmPrintEtiquetasStock;
begin
  if FQryMain.IsEmpty then Exit;

  LPrintDlg := TfrmPrintEtiquetasStock.Create(Self);
  try
    LPrintDlg.StockId := FQryMain.FieldByName('id').AsInteger;
    LPrintDlg.ShowModal;
  finally
    LPrintDlg.Free;
  end;
end;

procedure TfrmStockEnvasado.btnInventarioClick(Sender: TObject);
var
  LInvForm: TfrmInventarioStockEnvasado;
begin
  LInvForm := TfrmInventarioStockEnvasado.Create(Application);
  try
    if LInvForm.ShowModal = mrOk then
      btnRefreshClick(nil);
  finally
    btnRefreshClick(nil);
  end;
end;

end.
