package fanch.multijeu.numbers.fragment;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.transition.Slide;
import android.support.transition.Transition;
import android.support.transition.TransitionManager;
import android.support.transition.Visibility;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.TranslateAnimation;
import android.widget.TextView;

import fanch.multijeu.R;
import fanch.multijeu.common.core.AnimationEndListener;
import fanch.multijeu.common.core.Saveable;
import fanch.multijeu.common.view.ChronoView;
import fanch.multijeu.numbers.data.Expression;
import fanch.multijeu.numbers.data.ExpressionSet;
import fanch.multijeu.numbers.data.OperationExpr;
import fanch.multijeu.numbers.widget.AssistedCalcWidget;
import fanch.multijeu.numbers.widget.CalcWidget;
import fanch.multijeu.numbers.widget.CorrectionWidget;
import fanch.multijeu.numbers.widget.NonAssistedCalcWidget;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;

public class NumberFragment extends Fragment
        implements  AssistedCalcWidget.CalcWidgetListener,
        CorrectionWidget.CorrectionListener,
        ChronoView.ChronoCallback {

    protected NumberViewModel m;

    protected View mRoot;
    protected TextView mTvResult;
    protected TextView mTvPerdu;
    protected TextView mTvBest;
    protected ChronoView mChrono;
    protected CalcWidget mWidget;
    protected AssistedCalcWidget mWidgetSimple;
    protected NonAssistedCalcWidget mWidgetComplexe;
    protected CorrectionWidget mCorrection;
    protected NumberFragmentDriver mListener;
    protected Boolean mIsInit=false;


    public enum PadStyle {
        ASSISTED,
        NON_ASSISTED
    }

    public static class Attrs extends Saveable {
        public int time=-1;
        public PadStyle style=PadStyle.ASSISTED;
    }

    public interface NumberFragmentDriver{
        void onLoose(ExpressionSet s, Expression e);
        void onWin(ExpressionSet s, Expression e);
        void onCorrectFinish();
        void onAnimationFinish();
        void onFragmentInit();
        void onBestChanged(int value);
    }

    public static NumberFragment newInstance(Attrs a) {
        NumberFragment x  = new NumberFragment();
        x.m=new NumberViewModel();
        Bundle b = new Bundle();
        b.putSerializable("attrs", a);
        x.setArguments(b);
        return x;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View v =  inflater.inflate(R.layout.number_fragment, container, false);
        mRoot=v;
        init(null);
        return v;
    }

    public void init(Attrs  attrs)
    {
        m=new NumberViewModel();
        m.attrs=((Attrs)getArguments().getSerializable("attrs"));
        //m.attrs=attrs;
        if(m.attrs==null) m.attrs=new Attrs();


        mTvResult=mRoot.findViewById(R.id.tv_result);
        mWidgetSimple=mRoot.findViewById(R.id.cw_number_simple);
        mWidgetComplexe=mRoot.findViewById(R.id.cw_number_complexe);
        mTvBest=mRoot.findViewById(R.id.tv_best);
        mChrono=mRoot.findViewById(R.id.chrono);
        mChrono.setListener(this);
        mTvPerdu=mRoot.findViewById(R.id.perdu);
        mTvPerdu.setVisibility(GONE);

        mCorrection=mRoot.findViewById(R.id.cw_correction);
        mCorrection.setListener(this);

        mTvResult.setText("    ");

        setStyle();

        mTvResult.setVisibility(View.INVISIBLE);
        synchronized (mIsInit)
        {
            mIsInit=true;
            if(mListener!=null)
                mListener.onFragmentInit();

        }
    }

    public void setStyle(PadStyle p)
    {
        m.attrs.style=p;
        setStyle();
    }

    protected void setStyle()
    {
        mWidget=(m.attrs.style==PadStyle.ASSISTED)?mWidgetSimple:mWidgetComplexe;
        mWidget.setListener(this);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // TODO: Use the ViewModel
    }


    String fillString(int x , int length)
    {
        String s = x+"";
        while(s.length()<length)
            s+=" ";
        return s;
    }

    @Override
    public void onValid() {

        if(m.bestResult!=null && m.attrs.style==PadStyle.ASSISTED) {
            if (m.bestResult.compute() == m.currentSet.resultInt) {
                mChrono.stop();
                win();
                return;
            }
        }else if(m.bestResult!=null){
            if (m.bestResult.compute() == m.currentSet.resultInt) {
                mChrono.stop();
                win();
                return;
            }else {
                loose();
                return;
            }
        }
    }

    @Override
    public void onClear()
    {
    }

    @Override
    public void onUndo()
    {
        mTvBest.setText("    ");
        mTvResult.setText("    ");
    }

    public void correct()
    {
        mChrono.stop();
        Transition tr = new Slide(Gravity.BOTTOM);
        tr.setDuration(1000);
        tr.addListener(new Transition.TransitionListener() {
            public void onTransitionStart(@NonNull Transition transition) {}
            public void onTransitionEnd(@NonNull Transition transition) {
                mChrono.hide();
                mCorrection.correction(m.currentSet);
            }
            public void onTransitionCancel(@NonNull Transition transition) {}
            public void onTransitionPause(@NonNull Transition transition) {}
            public void onTransitionResume(@NonNull Transition transition) {}
        });

        Transition tr2 = new Slide(Gravity.BOTTOM);
        tr2.setDuration(1000);
        TransitionManager.beginDelayedTransition(mWidget, tr);
        mWidget.setVisibility(GONE);
    }

    @Override
    public void onExpressionDone(Expression expr) {
        if(m.bestResult==null
                || Math.abs(m.currentSet.resultInt-expr.compute())
                <
                Math.abs(m.currentSet.resultInt-m.bestResult.compute())
        )
        {
            m.bestResult=expr.clone();
            if(mListener!=null)
                mListener.onBestChanged(m.bestResult.compute());
            mTvBest.setText(fillString(m.bestResult.compute(),4));
        }

        if(expr.compute()==m.currentSet.resultInt)
            onValid();
    }



    @Override
    public void onAnimEnd() {
        mTvResult.setVisibility(VISIBLE);
        Animation animation = new TranslateAnimation(512, 0,0, 0);
        animation.setDuration(500);
        animation.setAnimationListener(new AnimationEndListener() {
            public void onAnimationEnd(Animation animation) {
                startChrono();
                if(mListener!=null)
                    mListener.onAnimationFinish();
            }
        });
        mTvResult.startAnimation(animation);
    }

    protected void startChrono()
    {
        if(m.attrs.time<=0) return;
        mChrono.setDuration(m.attrs.time);
        mChrono.start();
        mChrono.invalidate();
    }


    public void newGame(ExpressionSet s)
    {
        showWidget();
        mTvResult.setVisibility(View.INVISIBLE);
        m.currentSet=s;
        mWidget.setNumbers(m.currentSet);
        mTvResult.setText(fillString(m.currentSet.resultInt,4));
        mTvBest.setText("    ");
        m.bestResult=null;
    }



    protected void showWidget()
    {
        if(m.attrs.time<0)
        {
            mChrono.hide();
        }else{
            mChrono.show();
        }


        Transition tr = new Slide(Gravity.BOTTOM);
        ((Slide) tr).setMode(Visibility.MODE_IN);
        tr.setDuration(500);

        TransitionManager.beginDelayedTransition(mWidget, tr);
        mWidget.setVisibility(VISIBLE);
    }

    @Override
    public void onDone() {
        if(mListener!=null)
            mListener.onCorrectFinish();
    }

    @Override
    public void onSend(Expression expr) {

    }

    @Override
    public void onEnd() {
        int r = m.currentSet.resultInt;
        int a = (m.bestResult!=null) ?(m.bestResult.compute()):0;
        Expression e = mWidget.getResult();
        int b = (e!=null)?e.compute():0;
        int aa=Math.abs(r-a);
        int bb=Math.abs(r-b);
        if(bb<aa)
            m.bestResult=e;
        if(aa==0 || bb==0)
            win();
        else
            loose();
    }

    protected void win()
    {
        final Activity va = getActivity();
        mTvPerdu.setText("Bien joué !");
        mTvPerdu.setTextColor(0xff5f9e2b);
        mTvPerdu.setVisibility(VISIBLE);

        Animation an = AnimationUtils.loadAnimation(getActivity(), R.anim.scale);
        an.setDuration(1000);
        an.setAnimationListener(new AnimationEndListener() {
            @Override
            public void onAnimationEnd(final Animation animation) {
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvPerdu.clearAnimation();
                        mTvPerdu.setVisibility(View.INVISIBLE);
                        if(mListener!=null)
                            mListener.onWin(m.currentSet, m.bestResult);
                    }
                });
            }
        });
        mTvPerdu.startAnimation(an);
    }

    protected void loose()
    {
        final Activity va = getActivity();
        mTvPerdu.setText("Perdu !");
        mTvPerdu.setTextColor(0xffcb2121);
        mTvPerdu.setVisibility(VISIBLE);


        Animation an = AnimationUtils.loadAnimation(getActivity(), R.anim.scale);
        an.setDuration(1000);
        an.setAnimationListener(new AnimationEndListener() {
            @Override
            public void onAnimationEnd(final Animation animation) {
                va.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTvPerdu.clearAnimation();
                        mTvPerdu.setVisibility(View.INVISIBLE);

                        if(mListener!=null)
                            mListener.onLoose(m.currentSet, m.bestResult);
                    }
                });
            }
        });
        mTvPerdu.startAnimation(an);
    }

    public void setListener(NumberFragmentDriver mListener) {
        this.mListener = mListener;
        synchronized (mIsInit)
        {
            if(mIsInit)
                mListener.onFragmentInit();
        }
    }
}
