unit frm_DiaDetalleProduccion;

interface

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

type
  TfrmDiaDetalleProduccion = class(TForm)
    pnlTop: TPanel;
    lblTitulo: TLabel;
    lblSubtitulo: TLabel;
    pnlBuscar: TPanel;
    lblBuscar: TLabel;
    edtBuscar: TEdit;
    pnlGridContainer: TPanel;
    dbgDetalle: TDBGrid;
    pnlBottom: TPanel;
    btnAbrirOrden: TBitBtn;
    btnNuevaOrden: TBitBtn;
    lblHint: TLabel;
    btnCerrar: TBitBtn;
    mtDetalle: TFDMemTable;
    dsDetalle: TDataSource;

    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure dbgDetalleDrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure dbgDetalleDblClick(Sender: TObject);
    procedure dbgDetalleKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure dbgDetalleTitleClick(Column: TColumn);
    procedure btnAbrirOrdenClick(Sender: TObject);
    procedure btnNuevaOrdenClick(Sender: TObject);
    procedure btnCerrarClick(Sender: TObject);
    procedure edtBuscarChange(Sender: TObject);
  private
    FFecha: TDate;
    FEmpresaId: Integer;
    procedure ConfigurarTabla;
    procedure ConfigurarColumnas;
    procedure CargarDatos;
    procedure AbrirOrdenSeleccionada;
  public
    property Fecha: TDate read FFecha write FFecha;
    property EmpresaId: Integer read FEmpresaId write FEmpresaId;
  end;

implementation

{$R *.dfm}

procedure TfrmDiaDetalleProduccion.FormCreate(Sender: TObject);
begin
  FFecha := Date;
  FEmpresaId := StrToIntDef(dmgMain.CurrentCompanyId, 1);
  ConfigurarTabla;
  ConfigurarColumnas;
end;

procedure TfrmDiaDetalleProduccion.FormShow(Sender: TObject);
var
  LFechaStr: string;
begin
  LFechaStr := FormatDateTime('dddd, d "de" mmmm "de" yyyy', FFecha);
  if Length(LFechaStr) > 0 then
    LFechaStr[1] := UpCase(LFechaStr[1]);

  lblTitulo.Caption := 'Órdenes de Producción del Día: ' + LFechaStr;
  Caption := 'Órdenes de Producción — ' + FormatDateTime('dd/MM/yyyy', FFecha);

  CargarDatos;
  edtBuscar.Text := '';
  if dbgDetalle.CanFocus then
    dbgDetalle.SetFocus;
end;

procedure TfrmDiaDetalleProduccion.ConfigurarTabla;
begin
  mtDetalle.Close;
  mtDetalle.FieldDefs.Clear;
  mtDetalle.FieldDefs.Add('orden_id', ftInteger);
  mtDetalle.FieldDefs.Add('linea_id', ftInteger);
  mtDetalle.FieldDefs.Add('numero_orden', ftString, 30);
  mtDetalle.FieldDefs.Add('orden_estado', ftString, 20);
  mtDetalle.FieldDefs.Add('prioridad', ftString, 20);
  mtDetalle.FieldDefs.Add('obrador_nombre', ftString, 100);
  mtDetalle.FieldDefs.Add('id_pedido', ftInteger);
  mtDetalle.FieldDefs.Add('numero_pedido', ftString, 30);
  mtDetalle.FieldDefs.Add('id_articulo', ftInteger);
  mtDetalle.FieldDefs.Add('articulo_nombre', ftString, 150);
  mtDetalle.FieldDefs.Add('cantidad', ftFloat);
  mtDetalle.FieldDefs.Add('cantidad_fabricada', ftFloat);
  mtDetalle.FieldDefs.Add('linea_estado', ftString, 20);
  mtDetalle.FieldDefs.Add('observaciones', ftString, 255);
  mtDetalle.CreateDataSet;

  dsDetalle.DataSet := mtDetalle;
  dbgDetalle.DataSource := dsDetalle;
end;

procedure TfrmDiaDetalleProduccion.ConfigurarColumnas;
begin
  dbgDetalle.Columns.Clear;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'linea_estado';
    Title.Caption := 'Estado';
    Width := 105;
    Alignment := taCenter;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'numero_orden';
    Title.Caption := 'Nº Orden';
    Width := 115;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'obrador_nombre';
    Title.Caption := 'Obrador';
    Width := 140;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'articulo_nombre';
    Title.Caption := 'Artículo a Fabricar';
    Width := 250;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'cantidad';
    Title.Caption := 'Requerida';
    Width := 75;
    Alignment := taRightJustify;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'cantidad_fabricada';
    Title.Caption := 'Fabricada';
    Width := 75;
    Alignment := taRightJustify;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'numero_pedido';
    Title.Caption := 'Pedido';
    Width := 95;
    Alignment := taCenter;
  end;

  with dbgDetalle.Columns.Add do
  begin
    FieldName := 'observaciones';
    Title.Caption := 'Observaciones de Línea / Elaboración';
    Width := 280;
  end;
end;

procedure TfrmDiaDetalleProduccion.CargarDatos;
var
  LQry: TFDQuery;
  LTotalUds: Double;
  LTotalArticulos: Integer;
begin
  mtDetalle.Close;
  mtDetalle.Open;

  LQry := TFDQuery.Create(nil);
  try
    LQry.Connection := dmgMain.dbConn;
    LQry.SQL.Text :=
      'SELECT op.id AS orden_id, op.numero_orden, op.fecha_produccion, op.estado AS orden_estado, ' +
      '       op.prioridad, op.id_obrador, COALESCE(o.nombre, ''(Sin Obrador)'') AS obrador_nombre, ' +
      '       op.id_pedido, COALESCE(p.numero_pedido, ''—'') AS numero_pedido, ' +
      '       opl.id AS linea_id, opl.id_articulo, ' +
      '       COALESCE(a.descripcion, CONCAT(''Art. #'', opl.id_articulo)) AS articulo_nombre, ' +
      '       opl.cantidad, opl.cantidad_fabricada, opl.observaciones AS linea_observaciones, ' +
      '       opl.estado AS linea_estado ' +
      'FROM ge_ordenes_produccion op ' +
      'INNER JOIN ge_ordenes_produccion_lineas opl ON op.id = opl.id_orden ' +
      'LEFT JOIN ge_articulos a ON opl.id_articulo = a.id ' +
      'LEFT JOIN ge_obradores o ON op.id_obrador = o.id ' +
      'LEFT JOIN ge_pedidos p ON op.id_pedido = p.id ' +
      'WHERE op.empresa_id = :empresa_id ' +
      '  AND op.fecha_produccion = :fecha ' +
      'ORDER BY op.numero_orden ASC, opl.id ASC';
    LQry.ParamByName('empresa_id').AsInteger := FEmpresaId;
    LQry.ParamByName('fecha').AsDate := FFecha;
    LQry.Open;

    LTotalUds := 0.0;
    LTotalArticulos := 0;

    mtDetalle.DisableControls;
    try
      while not LQry.Eof do
      begin
        mtDetalle.Append;
        mtDetalle.FieldByName('orden_id').AsInteger := LQry.FieldByName('orden_id').AsInteger;
        mtDetalle.FieldByName('linea_id').AsInteger := LQry.FieldByName('linea_id').AsInteger;
        mtDetalle.FieldByName('numero_orden').AsString := LQry.FieldByName('numero_orden').AsString;
        mtDetalle.FieldByName('orden_estado').AsString := LQry.FieldByName('orden_estado').AsString;
        mtDetalle.FieldByName('prioridad').AsString := LQry.FieldByName('prioridad').AsString;
        mtDetalle.FieldByName('obrador_nombre').AsString := LQry.FieldByName('obrador_nombre').AsString;
        mtDetalle.FieldByName('id_pedido').AsInteger := LQry.FieldByName('id_pedido').AsInteger;
        mtDetalle.FieldByName('numero_pedido').AsString := LQry.FieldByName('numero_pedido').AsString;
        mtDetalle.FieldByName('id_articulo').AsInteger := LQry.FieldByName('id_articulo').AsInteger;
        mtDetalle.FieldByName('articulo_nombre').AsString := LQry.FieldByName('articulo_nombre').AsString;
        mtDetalle.FieldByName('cantidad').AsFloat := LQry.FieldByName('cantidad').AsFloat;
        mtDetalle.FieldByName('cantidad_fabricada').AsFloat := LQry.FieldByName('cantidad_fabricada').AsFloat;
        mtDetalle.FieldByName('linea_estado').AsString := LQry.FieldByName('linea_estado').AsString;
        mtDetalle.FieldByName('observaciones').AsString := LQry.FieldByName('linea_observaciones').AsString;
        mtDetalle.Post;

        LTotalUds := LTotalUds + LQry.FieldByName('cantidad').AsFloat;
        Inc(LTotalArticulos);
        LQry.Next;
      end;
      mtDetalle.First;
    finally
      mtDetalle.EnableControls;
    end;

    lblSubtitulo.Caption :=
      Format('📊 %d producto(s) programado(s)  •  %g unidades totales a elaborar',
             [LTotalArticulos, LTotalUds]);
  finally
    LQry.Free;
  end;
end;

procedure TfrmDiaDetalleProduccion.dbgDetalleDrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
  LCanvas: TCanvas;
  LText: string;
  LBadgeColor, LTextColor: TColor;
  LBadgeRect, LDrawRect: TRect;
  LAlignFlags: Cardinal;
begin
  LCanvas := dbgDetalle.Canvas;

  if (gdSelected in State) or (gdFocused in State) then
  begin
    LCanvas.Brush.Color := $00F5EBE1; // Azul suave selección
    LCanvas.Font.Color := clBlack;
  end
  else
  begin
    if mtDetalle.RecNo mod 2 = 0 then
      LCanvas.Brush.Color := $00FAFBFD
    else
      LCanvas.Brush.Color := clWhite;
    LCanvas.Font.Color := clBlack;
  end;

  LCanvas.FillRect(Rect);

  LDrawRect := Rect;
  LDrawRect.Left := LDrawRect.Left + 4;
  LDrawRect.Right := LDrawRect.Right - 4;

  if Column.FieldName = 'linea_estado' then
  begin
    LText := Column.Field.AsString;
    if LText = 'COMPLETADA' then
    begin
      LBadgeColor := $00EAF7EC;
      LTextColor := $001B6B22;
    end
    else if LText = 'EN_PROCESO' then
    begin
      LBadgeColor := $00FEF3EB;
      LTextColor := $00C06000;
    end
    else
    begin
      LBadgeColor := $00F1F5F9;
      LTextColor := $00334155;
    end;

    LBadgeRect := Rect;
    InflateRect(LBadgeRect, -3, -2);
    LCanvas.Brush.Color := LBadgeColor;
    LCanvas.Pen.Color := LBadgeColor;
    LCanvas.RoundRect(LBadgeRect.Left, LBadgeRect.Top, LBadgeRect.Right, LBadgeRect.Bottom, 4, 4);

    LCanvas.Font.Size := 8;
    LCanvas.Font.Style := [fsBold];
    LCanvas.Font.Color := LTextColor;
    DrawText(LCanvas.Handle, PChar(LText), Length(LText), LBadgeRect,
             DT_CENTER or DT_VCENTER or DT_SINGLELINE);
  end
  else if Column.FieldName = 'numero_orden' then
  begin
    LCanvas.Font.Style := [fsBold];
    LCanvas.Font.Color := $00855A2E;
    LText := Column.Field.AsString;
    DrawText(LCanvas.Handle, PChar(LText), Length(LText), LDrawRect,
             DT_LEFT or DT_VCENTER or DT_SINGLELINE);
  end
  else
  begin
    LText := Column.Field.DisplayText;

    if Column.Alignment = taRightJustify then
      LAlignFlags := DT_RIGHT
    else if Column.Alignment = taCenter then
      LAlignFlags := DT_CENTER
    else
      LAlignFlags := DT_LEFT;

    DrawText(LCanvas.Handle, PChar(LText), Length(LText), LDrawRect,
             DT_VCENTER or DT_SINGLELINE or DT_END_ELLIPSIS or LAlignFlags);
  end;
end;

procedure TfrmDiaDetalleProduccion.AbrirOrdenSeleccionada;
var
  LOrdenId: Integer;
  LEditor: TfrmOrdenProduccionEditor;
begin
  if mtDetalle.IsEmpty then Exit;

  LOrdenId := mtDetalle.FieldByName('orden_id').AsInteger;
  if LOrdenId <= 0 then Exit;

  LEditor := TfrmOrdenProduccionEditor.Create(Application);
  try
    LEditor.OrdenId := LOrdenId;
    LEditor.InitialFechaProduccion := FFecha;
    if LEditor.ShowModal = mrOk then
      CargarDatos;
  finally
    LEditor.Free;
  end;
end;

procedure TfrmDiaDetalleProduccion.dbgDetalleDblClick(Sender: TObject);
begin
  AbrirOrdenSeleccionada;
end;

procedure TfrmDiaDetalleProduccion.dbgDetalleKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_RETURN then
  begin
    Key := 0;
    AbrirOrdenSeleccionada;
  end
  else if Key = VK_ESCAPE then
  begin
    Key := 0;
    ModalResult := mrOk;
  end;
end;

procedure TfrmDiaDetalleProduccion.dbgDetalleTitleClick(Column: TColumn);
begin
  if mtDetalle.Active and (Column.FieldName <> '') then
    mtDetalle.IndexFieldNames := Column.FieldName;
end;

procedure TfrmDiaDetalleProduccion.btnAbrirOrdenClick(Sender: TObject);
begin
  AbrirOrdenSeleccionada;
end;

procedure TfrmDiaDetalleProduccion.btnNuevaOrdenClick(Sender: TObject);
var
  LEditor: TfrmOrdenProduccionEditor;
begin
  LEditor := TfrmOrdenProduccionEditor.Create(Application);
  try
    LEditor.OrdenId := 0;
    LEditor.InitialFechaProduccion := FFecha;
    if LEditor.ShowModal = mrOk then
      CargarDatos;
  finally
    LEditor.Free;
  end;
end;

procedure TfrmDiaDetalleProduccion.btnCerrarClick(Sender: TObject);
begin
  ModalResult := mrOk;
end;

procedure TfrmDiaDetalleProduccion.edtBuscarChange(Sender: TObject);
var
  LTerm: string;
begin
  LTerm := Trim(edtBuscar.Text);
  if LTerm = '' then
    mtDetalle.Filtered := False
  else
  begin
    mtDetalle.Filter :=
      Format('(articulo_nombre LIKE %s) OR (numero_orden LIKE %s) OR (obrador_nombre LIKE %s) OR (numero_pedido LIKE %s)',
             [QuotedStr('%' + LTerm + '%'), QuotedStr('%' + LTerm + '%'),
              QuotedStr('%' + LTerm + '%'), QuotedStr('%' + LTerm + '%')]);
    mtDetalle.Filtered := True;
  end;
end;

end.
