How can I check if a function can be written as $a * \sin (b * x + c) + d$?

Here is a differential equations/operator approach, leading to mathematics-based solutions instead of expression-matching ones. As the OP observes, matching algebraic expressions with expression patterns can be tricky, despite Mathematica's Optional patterns and Default values. For trigonometric functions it is usually trickier since, as @alx observes, trig functions have automatic simplification rules that change, for instance, Sin[t + Pi/2] to Cos[t]. Sometimes a mathematical approach is simpler or more robust.

Mathematical background

The expression $y = a * \sin (b * x + c)$ is the general solution to $$y'' + b^2 y = 0 \,,$$ and thus $y = a * \sin (b * x + c) + d$ is the general solution to $$y''' + b^2 y' = 0\,.\tag{1}$$ Even further, it is the general solution to $${d \over dx} {y''' \over y'} = {d \over dx} \left(-b^2\right) \,,$$ or equivalently $$y'y^{(4)}-y''y''' = 0 \,.\tag{2}$$ Equation (2) is equivalent to the vanishing of the second-order Wronskian of $y'$ and $y'''$, $$W \equiv \left|\matrix{ y' & y''' \\ y'' & y^{(4)} \\}\right| = 0 \,. \tag{3}$$ The condition $W=0$ is equivalent to $y'$ and $y'''$ being linearly dependent. A fourth-order ODE is as far as we can go, since the form $y = a * \sin (b * x + c) + d$ has four parameters.

Solution methods

A solution based on (1), using the internal, undocumented function Periodic`PeriodicFunctionPeriod is the following:

ClearAll[sinQ];
sinQ[f_, x_] := 
  With[{b = 2 Pi/Periodic`PeriodicFunctionPeriod[f, x]},
   Simplify[D[f, {x, 3}] + b^2 D[f, x]] === 0 /; FreeQ[b, $Failed]];
sinQ[__] = False;

A solution based on (2) is the following:

ClearAll[sinQ];
sinQ[f_, x_] := 
  Simplify[D[f, {x, 1}] D[f, {x, 4}] - D[f, {x, 2}] D[f, {x, 3}]] === 0;

And a solution based on (3), using the alternative PossibleZeroQ to simplifying the Wronskian, is the following:

ClearAll[sinQ];
sinQ[f_, x_] := 
  PossibleZeroQ[Det@Partition[Rest@NestList[D[#, x] &, f, 4], 2]];

Examples

sinQ[a*Sin[b*x + c] + d, x]
(*  True  *)

sinQ[5 Sin[4 (t - 1)] + Cos[2 t]^2 - 1, t]
(*  True  *)

sinQ[5 Sin[4 (t - 1)] + Cos[4 t]^2, t]
(*  False  *)

Note: Only the method that uses PossibleZeroQ works on the following example, which has approximate real parameter values:

sinQ[5 Sin[4. (t - 1)] + Cos[2. t + 0.1]^2, t]
(*  True  *)

One can use PossibleZeroQ in the other methods. It will work with the second example but not with the first, because Periodic`PeriodicFunctionPeriod fails to recognize the function with approximate coefficients as periodic. One could Rationalize the argument f in that case, if one wanted to extend that method to such as examples as this last one.

Addendum

It wasn't asked for but here is a way to compute the parameters. One can compute the offset d and amplitude b from integrals, which for a sine curve can be computed exactly and quickly with the trapezoid rule with a sampling of four points per period (see trapsample below). This can be used to verify sinQ, about whose accuracy a question arose.

ClearAll[sinParameters];
sinParameters[e_, t_] := Module[
   {df, aa, bb, cc, dd, trapsample},
   df = NestList[D[#, t] &, e, 4]; (* y''' + b^2 y' == 0 *)
   ( bb = Simplify@ Sqrt[-df[[4]]/df[[2]]];
     trapsample = Map[e /. t -> # &, Pi {1/4, 3/4, 0, 1/2, 1, 3/2}/bb];
     dd = Simplify@ Mean@ trapsample[[3 ;;]];
     aa = Simplify@ Sqrt[2 Mean[(trapsample[[;; 4]] - dd)^2]];
     cc = Simplify@ ArcSin[(e - dd)/aa /. t -> 0];
     If[df[[2]] != aa bb /. t -> -cc/bb, (* adjust quadrant of ArcSin *)
      aa = -aa;     (* alternatively, leave aa as is and set cc=Pi-cc *)
      cc = -cc
      ];
     Thread[{a, b, c, d} -> {aa, bb, cc, dd}]
     ) /; PossibleZeroQ[Det@Partition[Rest@df, 2]] (* same test as sinQ *)
   ];

On the second example above, @alx noted that @alx's method returns False. One can see that it can be written in the desired form from the following:

fn = 5 Sin[4 (t - 1)] + Cos[2 t]^2 - 1;
a * Sin[b*t + c] + d /. sinParameters[fn, t]
(*
  -(1/2)  -  1/2 Sqrt[101 - 20 Sin[4]] *
      Sin[ 4 t  -  ArcSin[(1 - 10 Sin[4])/Sqrt[101 - 20 Sin[4]]] ]
*)

fn - % // TrigToExp // FullSimplify
(*  0  *)

I wrote a symbolic analysis solver for the parameters, but the code is about twice as long and runs more than a 100 times more slowly. I didn't think it worth sharing.

sinQ[fn, t] // RepeatedTiming
sinParameters[fn, t] // RepeatedTiming
(*
  {0.000087, True}
  {0.00054, {
    a -> -(1/2) Sqrt[101 - 20 Sin[4]],
    b -> 4, 
    c -> -ArcSin[(1 - 10 Sin[4])/Sqrt[101 - 20 Sin[4]]],
    d -> -(1/2)}}
*)

You can use TrigReduce to come to form with multiple angles instead of powers and then use MatchQ to compare the result with Sin[...] pattern. I also use here Inactive[Sin] to keep results of conversion Cos terms to corresponding Sin terms:

MatchQ[(TrigReduce[expr]//Expand)/.{Sin[x_] -> Inactive[Sin][x],
Cos[x_] -> Inactive[Sin][x + \[Pi]/2]},
a_. Inactive[Sin][b_. x + c_.] + d_. /; FreeQ[d, x]

So this will match only to a Sin[b x+c]+d, where all a, b, c, d are constants.