import math

import numpy
import sympy

from .. import nsphere
from ..helpers import article, fsd, pm, untangle
from ._helpers import Enr2Scheme

citation = article(
    authors=["A.H. Stroud"],
    title="Some Seventh Degree Integration Formulas for Symmetric Regions",
    journal="SIAM J. Numer. Anal.",
    volume="4",
    number="1",
    pages="37–44",
    url="https://doi.org/10.1137/0704004",
)


def _stroud_1967_7_2(n, variant_a, symbolic):
    sqrt = sympy.sqrt if symbolic else math.sqrt
    pi = sympy.pi if symbolic else math.pi

    if variant_a:
        # the points/weights are complex-valued for n >= 9; one could permit that
        assert n in [2, 3, 4, 6, 7]
        p_m = +1
    else:
        assert n in [3, 4]
        p_m = -1

    sqrt38n = sqrt(3 * (8 - n))

    r2 = (3 * (8 - n) - p_m * (n - 2) * sqrt38n) / 2 / (5 - n)
    s2 = (3 * n - p_m * 2 * sqrt38n) / 2 / (3 * n - 8)
    t2 = (6 + p_m * sqrt38n) / 2
    B = (8 - n) / r2 ** 3 / 8
    C = 1 / s2 ** 3 / 2 ** (n + 3)
    D = 1 / t2 ** 3 / 16
    A = 1 - 2 * n * B - 2 ** n * C - 2 * n * (n - 1) * D

    r = sqrt(r2)
    s = sqrt(s2)
    t = sqrt(t2)

    data = [
        (A, numpy.full((1, n), 0)),
        (B, fsd(n, (r, 1))),
        (C, pm(n, s)),
        (D, fsd(n, (t, 2))),
    ]

    points, weights = untangle(data)
    weights *= sqrt(pi) ** n

    name = "Stroud 1967-7 2 (variant {})".format("a" if variant_a else "b")
    return Enr2Scheme(name, n, weights, points, 7, citation)


def stroud_1967_7_2a(n, symbolic=False):
    return _stroud_1967_7_2(n, True, symbolic)


def stroud_1967_7_2b(n, symbolic=False):
    return _stroud_1967_7_2(n, False, symbolic)


def stroud_1967_7_4(n, symbolic=False):
    frac = sympy.Rational if symbolic else lambda a, b: a / b
    sqrt = sympy.sqrt if symbolic else math.sqrt
    gamma = sympy.gamma if symbolic else math.gamma

    assert n >= 3

    sqrt2n2 = sqrt(2 * (n + 2))
    r1, r2 = [sqrt((n + 2 - p_m * sqrt2n2) / 2) for p_m in [+1, -1]]
    g = gamma(frac(n, 2))
    A1, A2 = [(n + 2 + p_m * sqrt2n2) / 4 / (n + 2) * g for p_m in [+1, -1]]

    s = nsphere.stroud_1967(n)

    points = numpy.concatenate([r1 * s.points, r2 * s.points])
    weights = numpy.concatenate([A1 * s.weights, A2 * s.weights])
    return Enr2Scheme("Stroud 1967-7 4", n, weights, points, 7, citation)

@@ -1661,43 +1661,51 @@
 def 
-stroud_1967_7_4(n, symbolic=False):
+_gamma_n_2(n, symbolic):%0A    # gamma(n / 2)
 %0A   
@@ -1816,21 +1816,18 @@
 qrt%0A    
-gamma
+pi
  = sympy
@@ -1827,21 +1827,18 @@
 = sympy.
-gamma
+pi
  if symb
@@ -1852,21 +1852,269 @@
 se math.
-gamma
+pi%0A%0A    if n %25 2 == 0:%0A        return math.factorial(n // 2 - 1)%0A%0A    n2 = n // 2%0A    return frac(math.factorial(2 * n2), 4 ** n2 * math.factorial(n2)) * sqrt(pi)%0A%0A%0Adef stroud_1967_7_4(n, symbolic=False):%0A    sqrt = sympy.sqrt if symbolic else math.sqrt
 %0A%0A    as
@@ -2239,24 +2239,30 @@
 g = 
+_
 gamma
-(frac(n, 2)
+_n_2(n, symbolic
 )%0A  

save one gamma function