import numpy as np
import sympy as sp
from sympy.printing.c import ccode as _ccode

ccode = lambda *args: _ccode(*args, standard='C89')

def stringify(basis, keys=None, symbolic=False, latex=True):
    """
    Eventually to replace shps.plane._stringify.
    """
    A    = basis.vandermonde()
    func = lambda x,y: [eval(t,dict(x=x,y=y)) for t in basis.terms]

    if keys is None:
        keys = list(basis.nodes.keys())


    b = np.zeros(len(A))

    output = ""

    try:
        Ainv = np.linalg.inv(A)
        Ainv = None

    except:
        Ainv = sp.Matrix(A).inv()


    if latex:
        x,y = sp.symbols("xi eta")

    else:
        _xi = sp.IndexedBase("xi", shape=(2,))
        x,y = _xi[0], _xi[1]
        # x,y = sp.symbols(" ".join(f"xi_{i}" for i in range(2)))

    for i in range(len(A)):
        b[:] = 0.0
        b[i] = 1.0
        if Ainv is not None:
            C = Ainv@b

        else:
            C = np.linalg.solve(A,b)


        exp = sum(sp.nsimplify(c, rational=True, full=True, tolerance=1e-10)*t
                  for c,t in zip(C, func(x,y)))

        _coef, expr = sp.factor(exp).as_coeff_Mul()

        if _coef == 1:
            coef = ""

        else:
            coef = sp.latex(_coef) if latex else ccode(_coef) + "*"

        if latex:
            output = "\n".join((output, f"N_{{{keys[i]}}} &= {coef} {sp.latex(_simplify(expr))} \\\\"))

        else:
            expr.replace(
                 lambda x: x.is_Pow and x.exp > 0,
                 lambda x: sp.Mul(*[x.base]*x.exp, evaluate=False))
            output = "\n".join((output, f"    shp[{i}][0] = {' '*bool(_coef>0)}{coef}{ccode((expr))};"))
            output = "\n".join((output, f"    shp[{i}][1] = {' '*bool(_coef>0)}{coef}({ccode((expr.diff(x)))});"))
            output = "\n".join((output, f"    shp[{i}][2] = {' '*bool(_coef>0)}{coef}({ccode((expr.diff(y)))});"))

    if latex:
        return f"$$\\begin{{aligned}}{output}\n\\end{{aligned}}$$"

    else:
        return output

