unit frm_Presupuestos;

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;

type
  TfrmPresupuestos = class(TfrmBaseList)
    cbSeries: TComboBox;
    cbPeriodo: TComboBox;
    btnDocsRelacionados: TSpeedButton;

    procedure FormShow(Sender: TObject);
    procedure btnRefreshClick(Sender: TObject); override;
    procedure btnNewClick(Sender: TObject); override;
    procedure btnEditClick(Sender: TObject); override;
    procedure btnDeleteClick(Sender: TObject); override;
    procedure cbFilterChange(Sender: TObject);
    procedure btnDocsRelacionadosClick(Sender: TObject);
    procedure btnPrintClick(Sender: TObject); override;
  private
  public
    { Public declarations }
  end;

var
  frmPresupuestos: TfrmPresupuestos;

implementation

uses
  dmg_Main, frm_PresupuestosEditor, System.DateUtils, frm_DocumentosRelacionados, uPresupuestoPrintService;

{$R *.dfm}

procedure TfrmPresupuestos.FormShow(Sender: TObject);
var
  Qry: TFDQuery;
begin
  DateFilterField := 'fecha';
  StatusFilterField := 'estado';
  StatusValues.Add('Pendiente');
  StatusValues.Add('Aceptado');
  StatusValues.Add('Rechazado');
  StatusValues.Add('Facturado');
  AlphaFilterField := 'cliente';

  inherited;
  pnlSearch.Visible := True;
  lblSearch.Caption := 'Buscar Presupuesto:';

  // Cargar series reales desde ge_series
  cbSeries.Items.Clear;
  cbSeries.Items.Add('Todas Series');
  cbSeries.ItemIndex := 0;

  Qry := TFDQuery.Create(nil);
  try
    Qry.Connection := dmgMain.dbConn;
    Qry.SQL.Text := 'SELECT DISTINCT serie, por_defecto FROM ge_series WHERE activo = 1 AND empresa_id = :emp ORDER BY serie';
    Qry.ParamByName('emp').AsString := dmgMain.CurrentCompanyId;
    Qry.Open;
    while not Qry.Eof do
    begin
      cbSeries.Items.Add(Qry.FieldByName('serie').AsString);
      if Qry.FieldByName('por_defecto').AsInteger <> 0 then
        cbSeries.ItemIndex := cbSeries.Items.Count - 1;
      Qry.Next;
    end;
  finally
    Qry.Free;
  end;

  // Refrescar para aplicar el filtro de la serie por defecto inmediatamente
  btnRefreshClick(nil);
end;

procedure TfrmPresupuestos.btnDocsRelacionadosClick(Sender: TObject);
begin
  if FQryMain.IsEmpty or (FQryMain.FindField('id') = nil) or (FQryMain.FieldByName('id').AsString = '') then
  begin
    ShowMessage('Debe seleccionar un presupuesto para consultar sus documentos relacionados.');
    Exit;
  end;

  TfrmDocumentosRelacionados.MostrarDocumentos(Self, dvtPresupuesto, FQryMain.FieldByName('id').AsString,
    FQryMain.FieldByName('serie').AsString + '/' + FQryMain.FieldByName('numero').AsString);
end;

procedure TfrmPresupuestos.cbFilterChange(Sender: TObject);
begin
  btnRefreshClick(nil);
end;

procedure TfrmPresupuestos.btnRefreshClick(Sender: TObject);
var
  LSql: string;
  LSearch: string;
  LDateStart, LDateEnd: TDateTime;
  LUseDateFilter: Boolean;
begin
  if dmgMain.CurrentCompanyId = '' then
    Exit;

  LSearch := Trim(edtSearch.Text);
  FQryMain.Close;

  LSql := 'SELECT p.id, p.serie, p.numero, p.fecha, c.nombre_fiscal as cliente, p.total, p.estado ' +
          'FROM ge_presupuestos p ' +
          'LEFT JOIN ge_clientes c ON p.cliente_id = c.id ' +
          'WHERE p.empresa_id = :empresa ';

  if LSearch <> '' then
  begin
    LSql := LSql + 'AND (c.nombre_fiscal LIKE :search OR p.numero LIKE :search) ';
  end;

  // Filtro de Serie
  if Assigned(cbSeries) and (cbSeries.ItemIndex > 0) then
    LSql := LSql + 'AND p.serie = :serie_filter ';

  // Filtro de Periodo
  LUseDateFilter := False;
  if Assigned(cbPeriodo) and (cbPeriodo.ItemIndex > 0) then
  begin
    LUseDateFilter := True;
    LDateEnd := Date;
    case cbPeriodo.ItemIndex of
      1: // Este Mes
        LDateStart := StartOfAMonth(YearOf(Date), MonthOf(Date));
      2: // Mes Anterior
        begin
          LDateStart := IncMonth(StartOfAMonth(YearOf(Date), MonthOf(Date)), -1);
          LDateEnd := EndOfAMonth(YearOf(LDateStart), MonthOf(LDateStart));
        end;
      3: // Este Trimestre
        begin
          case MonthOf(Date) of
            1..3: LDateStart := StartOfAMonth(YearOf(Date), 1);
            4..6: LDateStart := StartOfAMonth(YearOf(Date), 4);
            7..9: LDateStart := StartOfAMonth(YearOf(Date), 7);
            else LDateStart := StartOfAMonth(YearOf(Date), 10);
          end;
        end;
      4: // Este Año
        LDateStart := StartOfAMonth(YearOf(Date), 1);
      5: // Año Anterior
        begin
          LDateStart := StartOfAMonth(YearOf(Date) - 1, 1);
          LDateEnd := EncodeDate(YearOf(Date) - 1, 12, 31);
        end;
    end;
    LSql := LSql + 'AND p.fecha >= :date_start AND p.fecha <= :date_end ';
  end;

  LSql := LSql + 'ORDER BY p.fecha DESC, p.numero DESC';

  FQryMain.SQL.Text := LSql;
  FQryMain.ParamByName('empresa').AsString := dmgMain.CurrentCompanyId;

  if LSearch <> '' then
    FQryMain.ParamByName('search').AsString := '%' + LSearch + '%';

  if Assigned(cbSeries) and (cbSeries.ItemIndex > 0) then
    FQryMain.ParamByName('serie_filter').AsString := cbSeries.Text;

  if LUseDateFilter then
  begin
    FQryMain.ParamByName('date_start').AsDate := LDateStart;
    FQryMain.ParamByName('date_end').AsDate := LDateEnd;
  end;

  FQryMain.Open;
  if FQryMain.FindField('id') <> nil then
    FQryMain.FieldByName('id').Visible := False;
end;

procedure TfrmPresupuestos.btnEditClick(Sender: TObject);
begin
  if FQryMain.IsEmpty then Exit;
  
  if not Assigned(frmPresupuestosEditor) then
    Application.CreateForm(TfrmPresupuestosEditor, frmPresupuestosEditor);
  
  frmPresupuestosEditor.ParentForm := Self;
  frmPresupuestosEditor.PresupuestoId := FQryMain.FieldByName('id').AsString;
  frmPresupuestosEditor.ShowModal;
  btnRefreshClick(nil);
end;

procedure TfrmPresupuestos.btnNewClick(Sender: TObject);
begin
  if not Assigned(frmPresupuestosEditor) then
    Application.CreateForm(TfrmPresupuestosEditor, frmPresupuestosEditor);
  
  frmPresupuestosEditor.ParentForm := Self;
  frmPresupuestosEditor.PresupuestoId := '';
  frmPresupuestosEditor.ShowModal;
  btnRefreshClick(nil);
end;

procedure TfrmPresupuestos.btnDeleteClick(Sender: TObject);
var
  LId: string;
begin
  if FQryMain.IsEmpty then Exit;
  
  if MessageDlg('¿Está seguro de que desea eliminar el presupuesto seleccionado?', mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
    Exit;

  LId := FQryMain.FieldByName('id').AsString;
  if LId = '' then Exit;

  dmgMain.dbConn.StartTransaction;
  try
    // 1. Borrar líneas de detalle
    dmgMain.qryExec.Close;
    dmgMain.qryExec.SQL.Text := 'DELETE FROM ge_presupuestos_lineas WHERE presupuesto_id = :id';
    dmgMain.qryExec.ParamByName('id').AsString := LId;
    dmgMain.qryExec.ExecSQL;

    // 2. Borrar cabecera
    dmgMain.qryExec.Close;
    dmgMain.qryExec.SQL.Text := 'DELETE FROM ge_presupuestos WHERE id = :id';
    dmgMain.qryExec.ParamByName('id').AsString := LId;
    dmgMain.qryExec.ExecSQL;

    dmgMain.dbConn.Commit;
    btnRefreshClick(nil);
    ShowMessage('Presupuesto eliminado con éxito.');
  except
    on E: Exception do
    begin
      dmgMain.dbConn.Rollback;
      ShowMessage('Error al eliminar el presupuesto: ' + E.Message);
    end;
  end;
end;

procedure TfrmPresupuestos.btnPrintClick(Sender: TObject);
var
  LIds: TArray<string>;
begin
  LIds := GetSelectedOrCurrentIds('id');
  if Length(LIds) = 0 then
  begin
    ShowMessage('Debe seleccionar al menos un presupuesto para imprimir.');
    Exit;
  end;

  TPresupuestoPrintService.ImprimirPresupuestos(Self, LIds, dbGridMain);
end;

end.
