unit frm_CalendarioLaboralEditor;

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, FireDAC.Stan.Param,
  uAppTheme, System.DateUtils;

type
  TfrmCalendarioLaboralEditor = class(TForm)
    pnlTop: TPanel;
    lblTitulo: TLabel;
    lblSubtitulo: TLabel;
    pnlBody: TPanel;
    lblModo: TLabel;
    rbFestivoIndividual: TRadioButton;
    rbVacacionesRango: TRadioButton;
    lblFecha: TLabel;
    dtpFecha: TDateTimePicker;
    lblFechaHasta: TLabel;
    dtpFechaHasta: TDateTimePicker;
    lblDescripcion: TLabel;
    edtDescripcion: TEdit;
    lblTipo: TLabel;
    cbTipo: TComboBox;
    lblEmpresa: TLabel;
    cbEmpresa: TComboBox;
    pnlBottom: TPanel;
    btnGuardar: TBitBtn;
    btnCancelar: TBitBtn;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure rbModoClick(Sender: TObject);
    procedure btnGuardarClick(Sender: TObject);
  private
    FFestivoId: Integer;
    FDefaultAnio: Integer;
    FDefaultEmpresaId: Integer;
    FModoVacacionesFijas: Boolean;
    procedure CargarEmpresas;
    procedure CargarDatos;
  public
    property FestivoId: Integer read FFestivoId write FFestivoId;
    property DefaultAnio: Integer read FDefaultAnio write FDefaultAnio;
    property DefaultEmpresaId: Integer read FDefaultEmpresaId write FDefaultEmpresaId;
    property ModoVacacionesFijas: Boolean read FModoVacacionesFijas write FModoVacacionesFijas;
  end;

var
  frmCalendarioLaboralEditor: TfrmCalendarioLaboralEditor;

implementation

uses
  dmg_Main, uDbErrorHandler;

{$R *.dfm}

procedure TfrmCalendarioLaboralEditor.FormCreate(Sender: TObject);
begin
  FFestivoId := 0;
  FDefaultAnio := YearOf(Date);
  FDefaultEmpresaId := 0;
  FModoVacacionesFijas := False;
end;

procedure TfrmCalendarioLaboralEditor.CargarEmpresas;
var
  LQry: TFDQuery;
  LIdx, LSelectedIdx: Integer;
  LEmpId: Integer;
begin
  cbEmpresa.Items.Clear;
  // Primer elemento: Todas las empresas (Ámbito global / Grupo)
  cbEmpresa.Items.AddObject('[Todas las Empresas / Grupo]', TObject(NativeInt(0)));
  LSelectedIdx := 0;

  LQry := TFDQuery.Create(nil);
  try
    LQry.Connection := dmgMain.dbConn;
    LQry.SQL.Text := 'SELECT id, nombre FROM ge_empresas WHERE activo = 1 ORDER BY nombre ASC';
    try
      LQry.Open;
      while not LQry.Eof do
      begin
        LEmpId := LQry.FieldByName('id').AsInteger;
        LIdx := cbEmpresa.Items.AddObject(LQry.FieldByName('nombre').AsString, TObject(NativeInt(LEmpId)));
        if LEmpId = FDefaultEmpresaId then
          LSelectedIdx := LIdx;
        LQry.Next;
      end;
    except
    end;
  finally
    LQry.Free;
  end;

  if (LSelectedIdx >= 0) and (LSelectedIdx < cbEmpresa.Items.Count) then
    cbEmpresa.ItemIndex := LSelectedIdx
  else
    cbEmpresa.ItemIndex := 0;
end;

procedure TfrmCalendarioLaboralEditor.FormShow(Sender: TObject);
begin
  TAppTheme.ApplyToForm(Self);
  CargarEmpresas;

  if FFestivoId > 0 then
  begin
    lblTitulo.Caption := '✏️ Modificar Día Festivo / Vacaciones';
    lblSubtitulo.Caption := 'Actualice la información del día seleccionado en el calendario laboral.';
    rbFestivoIndividual.Visible := False;
    rbVacacionesRango.Visible := False;
    lblModo.Visible := False;
    lblFechaHasta.Visible := False;
    dtpFechaHasta.Visible := False;
    CargarDatos;
  end
  else
  begin
    lblTitulo.Caption := '➕ Nuevo Festivo / Periodo de Vacaciones Fijas';
    lblSubtitulo.Caption := 'Introduzca los datos para el calendario laboral oficial.';
    rbFestivoIndividual.Visible := True;
    rbVacacionesRango.Visible := True;
    lblModo.Visible := True;

    if FDefaultAnio > 0 then
      dtpFecha.Date := EncodeDate(FDefaultAnio, MonthOf(Date), DayOf(Date))
    else
      dtpFecha.Date := Date;

    dtpFechaHasta.Date := dtpFecha.Date;

    if FModoVacacionesFijas then
    begin
      rbVacacionesRango.Checked := True;
      cbTipo.ItemIndex := cbTipo.Items.IndexOf('VACACIONES FIJAS');
      if cbTipo.ItemIndex = -1 then cbTipo.ItemIndex := 4;
      edtDescripcion.Text := 'Vacaciones Fijas / Cierre Colectivo';
    end
    else
    begin
      rbFestivoIndividual.Checked := True;
      cbTipo.ItemIndex := 0; // FESTIVO NACIONAL
      edtDescripcion.Clear;
    end;

    rbModoClick(Self);
  end;

  edtDescripcion.SetFocus;
end;

procedure TfrmCalendarioLaboralEditor.rbModoClick(Sender: TObject);
begin
  if FFestivoId > 0 then Exit;

  if rbVacacionesRango.Checked then
  begin
    lblFecha.Caption := 'Fecha Inicio:';
    lblFechaHasta.Visible := True;
    dtpFechaHasta.Visible := True;
    if cbTipo.Items.IndexOf('VACACIONES FIJAS') >= 0 then
      cbTipo.ItemIndex := cbTipo.Items.IndexOf('VACACIONES FIJAS');
    if Trim(edtDescripcion.Text) = '' then
      edtDescripcion.Text := 'Vacaciones Colectivas / Cierre Empresa';
  end
  else
  begin
    lblFecha.Caption := 'Fecha:';
    lblFechaHasta.Visible := False;
    dtpFechaHasta.Visible := False;
    if cbTipo.ItemIndex = cbTipo.Items.IndexOf('VACACIONES FIJAS') then
      cbTipo.ItemIndex := 0;
  end;
end;

procedure TfrmCalendarioLaboralEditor.CargarDatos;
var
  LQry: TFDQuery;
  LEmpId: Integer;
  LTipo: string;
  I: Integer;
begin
  LQry := TFDQuery.Create(nil);
  try
    LQry.Connection := dmgMain.dbConn;
    LQry.SQL.Text := 'SELECT id, id_empresa, fecha, descripcion, tipo FROM ge_festivos WHERE id = :id';
    LQry.ParamByName('id').AsInteger := FFestivoId;
    LQry.Open;

    if not LQry.IsEmpty then
    begin
      dtpFecha.Date := LQry.FieldByName('fecha').AsDateTime;
      edtDescripcion.Text := LQry.FieldByName('descripcion').AsString;
      LTipo := UpperCase(Trim(LQry.FieldByName('tipo').AsString));

      // Seleccionar Tipo en el combo
      cbTipo.ItemIndex := 0;
      for I := 0 to cbTipo.Items.Count - 1 do
      begin
        if SameText(cbTipo.Items[I], LTipo) or
           (Pos(LTipo, UpperCase(cbTipo.Items[I])) > 0) or
           ((LTipo = 'VACACIONES') and (Pos('VACACION', UpperCase(cbTipo.Items[I])) > 0)) then
        begin
          cbTipo.ItemIndex := I;
          Break;
        end;
      end;

      // Seleccionar Empresa en el combo
      LEmpId := LQry.FieldByName('id_empresa').AsInteger;
      for I := 0 to cbEmpresa.Items.Count - 1 do
      begin
        if NativeInt(cbEmpresa.Items.Objects[I]) = LEmpId then
        begin
          cbEmpresa.ItemIndex := I;
          Break;
        end;
      end;
    end;
  finally
    LQry.Free;
  end;
end;

procedure TfrmCalendarioLaboralEditor.btnGuardarClick(Sender: TObject);
var
  LQry: TFDQuery;
  LEmpresaId: Integer;
  LTipoVal: string;
  LCurDate, LEndDate: TDateTime;
  LUserId: string;
begin
  if Trim(edtDescripcion.Text) = '' then
  begin
    ShowMessage('Debe indicar una descripción o motivo para el día festivo/vacaciones.');
    edtDescripcion.SetFocus;
    ModalResult := mrNone;
    Exit;
  end;

  if (FFestivoId = 0) and rbVacacionesRango.Checked then
  begin
    if dtpFechaHasta.Date < dtpFecha.Date then
    begin
      ShowMessage('La fecha final no puede ser anterior a la fecha inicial.');
      dtpFechaHasta.SetFocus;
      ModalResult := mrNone;
      Exit;
    end;
  end;

  if cbEmpresa.ItemIndex >= 0 then
    LEmpresaId := NativeInt(cbEmpresa.Items.Objects[cbEmpresa.ItemIndex])
  else
    LEmpresaId := 0;

  LTipoVal := cbTipo.Text;
  if LTipoVal = '' then
    LTipoVal := 'FESTIVO NACIONAL';

  LUserId := dmgMain.CurrentUserId;
  if LUserId = '' then LUserId := '1';

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

    if FFestivoId > 0 then
    begin
      // Modificación de registro existente
      LQry.SQL.Text :=
        'UPDATE ge_festivos SET ' +
        '  id_empresa = :empresa, ' +
        '  fecha = :fecha, ' +
        '  descripcion = :desc, ' +
        '  tipo = :tipo, ' +
        '  id_user_update = :user, ' +
        '  updated_at = CURRENT_TIMESTAMP ' +
        'WHERE id = :id';

      if LEmpresaId = 0 then
        LQry.ParamByName('empresa').Value := Null
      else
        LQry.ParamByName('empresa').AsInteger := LEmpresaId;

      LQry.ParamByName('fecha').AsDate := dtpFecha.Date;
      LQry.ParamByName('desc').AsString := Trim(edtDescripcion.Text);
      LQry.ParamByName('tipo').AsString := LTipoVal;
      LQry.ParamByName('user').AsString := LUserId;
      LQry.ParamByName('id').AsInteger := FFestivoId;
      LQry.ExecSQL;
    end
    else
    begin
      // Alta nueva (Individual o Rango de fechas)
      if rbVacacionesRango.Checked then
      begin
        LCurDate := dtpFecha.Date;
        LEndDate := dtpFechaHasta.Date;
        while LCurDate <= LEndDate do
        begin
          LQry.Close;
          LQry.SQL.Text :=
            'INSERT INTO ge_festivos (id_empresa, fecha, descripcion, tipo, id_user_creator, id_user_update) ' +
            'VALUES (:empresa, :fecha, :desc, :tipo, :user, :user) ' +
            'ON DUPLICATE KEY UPDATE descripcion = VALUES(descripcion), tipo = VALUES(tipo), id_user_update = VALUES(id_user_update)';

          if LEmpresaId = 0 then
            LQry.ParamByName('empresa').Value := Null
          else
            LQry.ParamByName('empresa').AsInteger := LEmpresaId;

          LQry.ParamByName('fecha').AsDate := LCurDate;
          LQry.ParamByName('desc').AsString := Trim(edtDescripcion.Text);
          LQry.ParamByName('tipo').AsString := LTipoVal;
          LQry.ParamByName('user').AsString := LUserId;
          LQry.ExecSQL;

          LCurDate := IncDay(LCurDate, 1);
        end;
      end
      else
      begin
        LQry.Close;
        LQry.SQL.Text :=
          'INSERT INTO ge_festivos (id_empresa, fecha, descripcion, tipo, id_user_creator, id_user_update) ' +
          'VALUES (:empresa, :fecha, :desc, :tipo, :user, :user) ' +
          'ON DUPLICATE KEY UPDATE descripcion = VALUES(descripcion), tipo = VALUES(tipo), id_user_update = VALUES(id_user_update)';

        if LEmpresaId = 0 then
          LQry.ParamByName('empresa').Value := Null
        else
          LQry.ParamByName('empresa').AsInteger := LEmpresaId;

        LQry.ParamByName('fecha').AsDate := dtpFecha.Date;
        LQry.ParamByName('desc').AsString := Trim(edtDescripcion.Text);
        LQry.ParamByName('tipo').AsString := LTipoVal;
        LQry.ParamByName('user').AsString := LUserId;
        LQry.ExecSQL;
      end;
    end;

    ModalResult := mrOk;
  except
    on E: Exception do
    begin
      TDbErrorHandler.HandleException(E, LQry.SQL.Text);
      ModalResult := mrNone;
    end;
  end;
  LQry.Free;
end;

end.
