unit dlg_ClonarTarifa;

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, FireDAC.Comp.Client, Data.DB, System.UITypes, FireDAC.Stan.Param;

type
  TdlgClonarTarifa = class(TForm)
    pnlMain: TPanel;
    lblTitulo: TLabel;
    lblGrupo: TLabel;
    gbOrigen: TGroupBox;
    lblAnoOrigen: TLabel;
    lblInfoOrigen: TLabel;
    cbbAnoOrigen: TComboBox;
    gbDestino: TGroupBox;
    lblAnoDestino: TLabel;
    lblFechaDesde: TLabel;
    lblFechaHasta: TLabel;
    edtAnoDestino: TEdit;
    dtpFechaDesde: TDateTimePicker;
    dtpFechaHasta: TDateTimePicker;
    gbVariacion: TGroupBox;
    lblVariacionPct: TLabel;
    lblAyudaVariacion: TLabel;
    edtVariacionPct: TEdit;
    pnlBotones: TPanel;
    btnEjecutar: TBitBtn;
    btnCancelar: TBitBtn;

    procedure FormShow(Sender: TObject);
    procedure edtAnoDestinoChange(Sender: TObject);
    procedure cbbAnoOrigenChange(Sender: TObject);
    procedure btnEjecutarClick(Sender: TObject);
  private
    FGrupoId: string;
    FGrupoNombre: string;
    FGeneratedYear: Integer;

    procedure CargarAnosOrigen;
    procedure RecalcularFechasDestino;
  public
    property GrupoId: string read FGrupoId write FGrupoId;
    property GrupoNombre: string read FGrupoNombre write FGrupoNombre;
    property GeneratedYear: Integer read FGeneratedYear;

    class function Execute(AOwner: TComponent; const AGrupoId, AGrupoNombre: string; var AOutYear: Integer): Boolean;
  end;

var
  dlgClonarTarifa: TdlgClonarTarifa;

implementation

uses
  dmg_Main, uAppTheme;

{$R *.dfm}

class function TdlgClonarTarifa.Execute(AOwner: TComponent; const AGrupoId, AGrupoNombre: string; var AOutYear: Integer): Boolean;
var
  Dlg: TdlgClonarTarifa;
begin
  Result := False;
  Dlg := TdlgClonarTarifa.Create(AOwner);
  try
    Dlg.GrupoId := AGrupoId;
    Dlg.GrupoNombre := AGrupoNombre;
    if Dlg.ShowModal = mrOk then
    begin
      AOutYear := Dlg.GeneratedYear;
      Result := True;
    end;
  finally
    Dlg.Free;
  end;
end;

procedure TdlgClonarTarifa.FormShow(Sender: TObject);
var
  LNextYear: Word;
  Y, M, D: Word;
begin
  TAppTheme.ApplyToForm(Self);

  lblGrupo.Caption := 'Grupo de Clientes: ' + FGrupoNombre;

  DecodeDate(Date, Y, M, D);
  LNextYear := Y;
  if M >= 10 then // Si estamos a final de año, sugerir el año siguiente
    LNextYear := Y + 1;

  edtAnoDestino.Text := IntToStr(LNextYear);
  RecalcularFechasDestino;

  CargarAnosOrigen;
end;

procedure TdlgClonarTarifa.CargarAnosOrigen;
var
  Qry: TFDQuery;
  LHasNullDates: Boolean;
  LAno: Integer;
begin
  cbbAnoOrigen.Items.Clear;
  LHasNullDates := False;

  Qry := TFDQuery.Create(nil);
  try
    Qry.Connection := dmgMain.dbConn;
    Qry.SQL.Text :=
      'SELECT DISTINCT YEAR(valido_desde) as ano ' +
      'FROM ge_clientes_grupos_precios ' +
      'WHERE id_cliente_grupo = :grp AND valido_desde IS NOT NULL ' +
      'ORDER BY ano DESC';
    Qry.ParamByName('grp').AsString := FGrupoId;
    Qry.Open;

    while not Qry.Eof do
    begin
      LAno := Qry.FieldByName('ano').AsInteger;
      if LAno > 1900 then
        cbbAnoOrigen.Items.Add(IntToStr(LAno));
      Qry.Next;
    end;

    Qry.Close;
    Qry.SQL.Text :=
      'SELECT COUNT(*) FROM ge_clientes_grupos_precios ' +
      'WHERE id_cliente_grupo = :grp AND (valido_desde IS NULL OR valido_hasta IS NULL)';
    Qry.ParamByName('grp').AsString := FGrupoId;
    Qry.Open;

    if (not Qry.IsEmpty) and (Qry.Fields[0].AsInteger > 0) then
      LHasNullDates := True;

    if LHasNullDates or (cbbAnoOrigen.Items.Count = 0) then
      cbbAnoOrigen.Items.Add('(Tarifas Vigentes / Sin Fechas)');

    if cbbAnoOrigen.Items.Count > 0 then
      cbbAnoOrigen.ItemIndex := 0;
  finally
    Qry.Free;
  end;
end;

procedure TdlgClonarTarifa.edtAnoDestinoChange(Sender: TObject);
begin
  RecalcularFechasDestino;
end;

procedure TdlgClonarTarifa.RecalcularFechasDestino;
var
  LYear: Integer;
begin
  if TryStrToInt(Trim(edtAnoDestino.Text), LYear) and (LYear >= 2000) and (LYear <= 2100) then
  begin
    dtpFechaDesde.Date := EncodeDate(LYear, 1, 1);
    dtpFechaHasta.Date := EncodeDate(LYear, 12, 31);
  end;
end;

procedure TdlgClonarTarifa.cbbAnoOrigenChange(Sender: TObject);
begin
  // Permite actualizar ayuda informativa si fuera necesario
end;

procedure TdlgClonarTarifa.btnEjecutarClick(Sender: TObject);
var
  QryCheck, QryExec: TFDQuery;
  LTargetYear, LSourceYear: Integer;
  LCount, LExistingCount: Integer;
  LWhereSource: string;
  LVariacionPct: Double;
  LVarStr: string;
  LFactorMultiplicador: Double;
begin
  if not TryStrToInt(Trim(edtAnoDestino.Text), LTargetYear) or (LTargetYear < 2000) or (LTargetYear > 2100) then
  begin
    ShowMessage('Por favor, introduzca un año de destino válido (ej. 2026).');
    edtAnoDestino.SetFocus;
    Exit;
  end;

  if dtpFechaHasta.Date < dtpFechaDesde.Date then
  begin
    ShowMessage('La fecha de fin de validez debe ser posterior o igual a la fecha de inicio.');
    dtpFechaHasta.SetFocus;
    Exit;
  end;

  LVarStr := StringReplace(Trim(edtVariacionPct.Text), '%', '', [rfReplaceAll]);
  LVarStr := StringReplace(LVarStr, ',', '.', [rfReplaceAll]);
  LVariacionPct := StrToFloatDef(LVarStr, 0.0);
  LFactorMultiplicador := 1.0 + (LVariacionPct / 100.0);

  // Determinar condición WHERE de origen
  if TryStrToInt(cbbAnoOrigen.Text, LSourceYear) then
  begin
    LWhereSource :=
      'WHERE id_cliente_grupo = :grp ' +
      '  AND ((YEAR(valido_desde) = ' + IntToStr(LSourceYear) + ') ' +
      '       OR (valido_desde IS NULL AND YEAR(valido_hasta) = ' + IntToStr(LSourceYear) + '))';
  end
  else
  begin
    LWhereSource :=
      'WHERE id_cliente_grupo = :grp ' +
      '  AND (valido_desde IS NULL OR valido_hasta IS NULL)';
  end;

  QryCheck := TFDQuery.Create(nil);
  QryExec := TFDQuery.Create(nil);
  try
    QryCheck.Connection := dmgMain.dbConn;
    QryExec.Connection := dmgMain.dbConn;

    // 1. Comprobar cuántos artículos existen en el origen
    QryCheck.SQL.Text := 'SELECT COUNT(*) FROM ge_clientes_grupos_precios ' + LWhereSource;
    QryCheck.ParamByName('grp').AsString := FGrupoId;
    QryCheck.Open;
    LCount := QryCheck.Fields[0].AsInteger;
    QryCheck.Close;

    // Fallback: si no encontró con condición específica pero hay precios en el grupo, tomar todos los del grupo
    if LCount = 0 then
    begin
      QryCheck.SQL.Text := 'SELECT COUNT(*) FROM ge_clientes_grupos_precios WHERE id_cliente_grupo = :grp';
      QryCheck.ParamByName('grp').AsString := FGrupoId;
      QryCheck.Open;
      LCount := QryCheck.Fields[0].AsInteger;
      QryCheck.Close;

      if LCount > 0 then
        LWhereSource := 'WHERE id_cliente_grupo = :grp';
    end;

    if LCount = 0 then
    begin
      ShowMessage('No se encontraron artículos ni precios para el periodo origen seleccionado.');
      Exit;
    end;

    // 2. Comprobar si ya existen precios para el periodo destino
    QryCheck.SQL.Text :=
      'SELECT COUNT(*) FROM ge_clientes_grupos_precios ' +
      'WHERE id_cliente_grupo = :grp ' +
      '  AND valido_desde = :f_desde AND valido_hasta = :f_hasta';
    QryCheck.ParamByName('grp').AsString := FGrupoId;
    QryCheck.ParamByName('f_desde').AsDate := dtpFechaDesde.Date;
    QryCheck.ParamByName('f_hasta').AsDate := dtpFechaHasta.Date;
    QryCheck.Open;
    LExistingCount := QryCheck.Fields[0].AsInteger;
    QryCheck.Close;

    if LExistingCount > 0 then
    begin
      if MessageDlg(
           Format('Ya existen %d precio(s) registrados para el periodo del %s al %s.' + sLineBreak + sLineBreak +
                  '¿Desea reemplazarlos por los nuevos precios generados?',
                  [LExistingCount, DateToStr(dtpFechaDesde.Date), DateToStr(dtpFechaHasta.Date)]),
           mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
        Exit;

      // Borrar registros existentes del mismo periodo
      QryExec.SQL.Text :=
        'DELETE FROM ge_clientes_grupos_precios ' +
        'WHERE id_cliente_grupo = :grp ' +
        '  AND valido_desde = :f_desde AND valido_hasta = :f_hasta';
      QryExec.ParamByName('grp').AsString := FGrupoId;
      QryExec.ParamByName('f_desde').AsDate := dtpFechaDesde.Date;
      QryExec.ParamByName('f_hasta').AsDate := dtpFechaHasta.Date;
      QryExec.ExecSQL;
    end
    else
    begin
      if MessageDlg(
           Format('Se van a generar %d precios para el ejercicio %d' + sLineBreak +
                  'Periodo de validez: %s al %s' + sLineBreak +
                  'Variación aplicada: %.2f %%' + sLineBreak + sLineBreak +
                  '¿Desea continuar?',
                  [LCount, LTargetYear, DateToStr(dtpFechaDesde.Date), DateToStr(dtpFechaHasta.Date), LVariacionPct]),
           mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
        Exit;
    end;

    // 3. Ejecutar la clonación masiva
    QryExec.SQL.Text :=
      'INSERT INTO ge_clientes_grupos_precios ' +
      '(id_cliente_grupo, id_articulo, precio, valido_desde, valido_hasta, und_min, und_max, id_user_creator, id_user_update) ' +
      'SELECT :grp, id_articulo, ' +
      '       ROUND(precio * ' + StringReplace(FloatToStr(LFactorMultiplicador), ',', '.', [rfReplaceAll]) + ', 2), ' +
      '       :f_desde, :f_hasta, und_min, und_max, :user, :user ' +
      'FROM ge_clientes_grupos_precios ' + LWhereSource;
    QryExec.ParamByName('grp').AsString := FGrupoId;
    QryExec.ParamByName('f_desde').AsDate := dtpFechaDesde.Date;
    QryExec.ParamByName('f_hasta').AsDate := dtpFechaHasta.Date;
    QryExec.ParamByName('user').AsString := dmgMain.CurrentUserId;
    QryExec.ExecSQL;

    QryExec.Close;
    QryExec.SQL.Text := 'SELECT ROW_COUNT()';
    QryExec.Open;
    LCount := QryExec.Fields[0].AsInteger;
    QryExec.Close;

    FGeneratedYear := LTargetYear;

    ShowMessage(Format('¡Tarifa del ejercicio %d generada con éxito!' + sLineBreak +
                       'Se han creado %d artículos con sus precios.', [LTargetYear, LCount]));

    ModalResult := mrOk;
  finally
    QryCheck.Free;
    QryExec.Free;
  end;
end;

end.
