package com.orange.widget.ui;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.orange.widget.R;
import com.orange.widget.util.ModelViewerGUI;
import org.the3deer.android_3d_model_engine.camera.CameraController;
import org.the3deer.android_3d_model_engine.collision.CollisionController;
import org.the3deer.android_3d_model_engine.collision.CollisionEvent;
import org.the3deer.android_3d_model_engine.controller.TouchController;
import org.the3deer.android_3d_model_engine.controller.TouchEvent;
import org.the3deer.android_3d_model_engine.event.SelectedObjectEvent;
import org.the3deer.android_3d_model_engine.model.Projection;
import org.the3deer.android_3d_model_engine.services.SceneLoader;
import org.the3deer.android_3d_model_engine.view.FPSEvent;
import org.the3deer.android_3d_model_engine.view.ModelRenderer;
import org.the3deer.android_3d_model_engine.view.ModelSurfaceView;
import org.the3deer.android_3d_model_engine.view.ViewEvent;
import org.the3deer.util.android.ContentUtils;
import org.the3deer.util.android.FileUtils;
import org.the3deer.util.event.EventListener;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

/**
 * This activity represents the container for our 3D viewer.
 */
public class ModelActivity extends AppCompatActivity implements EventListener {
    private static final int REQUEST_CODE_LOAD_TEXTURE = 1000;
    private static final int FULLSCREEN_DELAY = 10000;
    /**
     * Type of model if file name has no extension (provided though content provider)
     */
    private int paramType;
    /**
     * The file to load. Passed as input parameter
     */
    private URI paramUri;
    /**
     * Enter into Android Immersive mode so the renderer is full screen or not
     */
    private boolean immersiveMode;
    /**
     * Background GL clear color. Default is light gray
     */
    private float[] backgroundColor = new float[]{0.0f, 0.5f, 0.0f, 1.0f};

    private ModelSurfaceView glView;
    private TouchController touchController;
    private SceneLoader scene;
    private ModelViewerGUI gui;
    private CollisionController collisionController;
    private Handler handler;
    private CameraController cameraController;
    private SensorManager sensorManager;
    private Sensor sensor;
    private ModelRenderer mRenderer;
    private List<String> datas =new ArrayList<>();
    private int counter = 0;
    private int downloadCount = 0;
    String objName = "";
    String mtlName = "";
    //是否能够触摸与缩放
    private boolean canTouch =false;
    private URI puri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i("ModelActivity", "onCreate: Loading activity... "+savedInstanceState);
        super.onCreate(savedInstanceState);
        // Try to get input parameters
        Bundle b = getIntent().getExtras();
        if (b != null) {
            try {
                if (b.getString("uri") != null) {
                    this.paramUri = new URI(b.getString("uri"));
                    Log.i("ModelActivity", "Params: uri '" + paramUri + "'");
                }
                this.paramType = b.getString("type") != null ? Integer.parseInt(b.getString("type")) : -1;
                this.immersiveMode = "true".equalsIgnoreCase(b.getString("immersiveMode"));

                if (b.getString("backgroundColor") != null) {
                    String[] backgroundColors = b.getString("backgroundColor").split(" ");
                    backgroundColor[0] = Float.parseFloat(backgroundColors[0]);
                    backgroundColor[1] = Float.parseFloat(backgroundColors[1]);
                    backgroundColor[2] = Float.parseFloat(backgroundColors[2]);
                    backgroundColor[3] = Float.parseFloat(backgroundColors[3]);
                }
            } catch (Exception ex) {
                Log.e("ModelActivity", "Error parsing activity parameters: " + ex.getMessage(), ex);
            }

        }
        handler = new Handler(getMainLooper());
        // Create our 3D scenario
        datas.add("https://appmanage.youcai168.cn/villain/villain_obj.obj");
        datas.add("https://appmanage.youcai168.cn/villain/villain_mtl");
        datas.add("https://appmanage.youcai168.cn/villain/villain_d.png");
        datas.add("https://appmanage.youcai168.cn/villain/villain_n.png");
        load3dModel();
    }

    private void toggleImmersive() {
        this.immersiveMode = !this.immersiveMode;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            return;
        }
        if (this.immersiveMode) {
            hideSystemUI();
        } else {
            showSystemUI();
        }
        Toast.makeText(this, "Fullscreen " + this.immersiveMode, Toast.LENGTH_SHORT).show();
    }

    private void hideSystemUIDelayed() {
        if (!this.immersiveMode) {
            return;
        }
        handler.removeCallbacksAndMessages(null);
        handler.postDelayed(this::hideSystemUI, FULLSCREEN_DELAY);

    }

    private void hideSystemUI() {
        if (!this.immersiveMode) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            hideSystemUIKitKat();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            hideSystemUIJellyBean();
        }
    }

    // This snippet hides the system bars.
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void hideSystemUIKitKat() {
        // Set the IMMERSIVE flag.
        // Set the content to appear under the system bars so that the content
        // doesn't resize when the system bars hide and show.
        final View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
                | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                | View.SYSTEM_UI_FLAG_IMMERSIVE);
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void hideSystemUIJellyBean() {
        final View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LOW_PROFILE);
    }

    // This snippet shows the system bars. It does this by removing all the flags
    // except for the ones that make the content appear under the system bars.
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void showSystemUI() {
        handler.removeCallbacksAndMessages(null);
        final View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            return;
        }
        switch (requestCode) {
            case REQUEST_CODE_LOAD_TEXTURE:
                // The URI of the selected file
                final Uri uri = data.getData();
                if (uri != null) {
                    Log.i("ModelActivity", "Loading texture '" + uri + "'");
                    try {
                        ContentUtils.setThreadActivity(this);
                        scene.loadTexture(null, uri);
                    } catch (IOException ex) {
                        Log.e("ModelActivity", "Error loading texture: " + ex.getMessage(), ex);
                        Toast.makeText(this, "Error loading texture '" + uri + "'. " + ex
                                .getMessage(), Toast.LENGTH_LONG).show();
                    } finally {
                        ContentUtils.setThreadActivity(null);
                    }
                }
        }
    }

    @Override
    public boolean onEvent(EventObject event) {
        if (event instanceof FPSEvent){
            gui.onEvent(event);
        }
        else if (event instanceof SelectedObjectEvent){
            gui.onEvent(event);
        }
        else if (event.getSource() instanceof MotionEvent){
            // event coming from glview
            touchController.onMotionEvent((MotionEvent) event.getSource());
        }
        else if (event instanceof CollisionEvent){
            scene.onEvent(event);
        }
        else if (event instanceof TouchEvent){
            TouchEvent touchEvent = (TouchEvent) event;
            if (touchEvent.getAction() == TouchEvent.Action.CLICK){
                if (!collisionController.onEvent(event)){
                    scene.onEvent(event);
                }
            } else {
                if (scene.getSelectedObject() != null) {
                    scene.onEvent(event);
                } else {
                    cameraController.onEvent(event);
                    scene.onEvent(event);
                    if (((TouchEvent) event).getAction() == TouchEvent.Action.PINCH) {
                        glView.onEvent(event);
                    }
                }
            }
        }
        else if (event instanceof ViewEvent) {
            ViewEvent viewEvent = (ViewEvent) event;
            if (viewEvent.getCode() == ViewEvent.Code.SURFACE_CHANGED) {
                cameraController.onEvent(viewEvent);
                touchController.onEvent(viewEvent);
                // process event in GUI
                if (gui != null) {
                    gui.setSize(viewEvent.getWidth(), viewEvent.getHeight());
                    gui.setVisible(true);
                }
            } else if (viewEvent.getCode() == ViewEvent.Code.PROJECTION_CHANGED){
                cameraController.onEvent(event);
            }
        }
        return true;
    }

    @Override
    public void onBackPressed() {
        if (immersiveMode) {
            toggleImmersive();
        } else {
            super.onBackPressed();
        }
    }


    private void load3dModel() {
        //文件是否已经下载
        for (String url : datas) {
            String fileName = url.substring(url.lastIndexOf('/') + 1);
            File destFile = new File(this.getExternalFilesDir("3dModel").toString(), fileName);
            if(url.contains("obj")){
                objName = url.substring(url.lastIndexOf('/') + 1);
            }else if(url.contains("mtl")){
                mtlName = url.substring(url.lastIndexOf('/') + 1);
            }
            if (destFile.exists()) {
                downloadCount +=1;
            }
        }
        Log.e("downloaded file= ",  "objName= "+objName+" mtlName= " + mtlName +" downloadCount= "+downloadCount);
        if(downloadCount == datas.size()){
            //已经存在了，直接加载
            //  parseMtlmappic(0x0000ff,objName,mtlName);
            File objFile = new File(this.getExternalFilesDir("3dModel").toString(),objName);
            if(objFile.isFile() && objFile.exists()){
                Uri uri = Uri.parse("file://" + objFile.getAbsolutePath());
                initScene(uri);
            }
        }else{
            //下载并保存
            save3dModelResourceToLocal(datas);
        }
    }

    private void initScene(Uri uri) {
        Log.i("ModelActivity", "Loading Scene...");
        try {
             puri = URI.create(uri.toString());
        } catch (Exception e) {
            // info: filesystem url may contain spaces, therefore we re-encode URI
            try {
                 puri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());
            } catch (URISyntaxException ex) {
                Toast.makeText(this, "Error: " + uri.toString(), Toast.LENGTH_LONG).show();
                return;
            }
        }
        scene = new SceneLoader(this, puri, paramType);
        scene.addListener(this);
        if (paramUri == null) {
            // final LoaderTask task = new DemoLoaderTask(this, null, scene);
            // task.execute();
        }
        try {
            Log.i("ModelActivity", "Loading GLSurfaceView...");
            setContentView(R.layout.activity_model);
            glView=  findViewById(R.id.surfaceView);
            glView.setBackgroundColor(backgroundColor);
            glView.setScene(scene);
            glView.addListener(this);
            glView.setCanTouch(canTouch);
           // mRenderer = new ModelRenderer(this, glView, backgroundColor,  this.scene);
          //  mRenderer.addListener(this);
           // glView.setRenderer(mRenderer);

            // glView = new ModelSurfaceView(this, backgroundColor, this.scene);
            // glView.addListener(this);
            // setContentView(glView);
//            scene.setView(glView);
        } catch (Exception e) {
            Log.e("ModelActivity", e.getMessage(), e);
            Toast.makeText(this, "Error loading OpenGL view:\n" + e.getMessage(), Toast.LENGTH_LONG).show();
        }
        try {
            Log.i("ModelActivity", "Loading TouchController...");
            touchController = new TouchController(this);
            touchController.addListener(this);
            if(!canTouch){
                touchController.removeListener(this);
            }
            //touchController.addListener(glView);
        } catch (Exception e) {
            Log.e("ModelActivity", e.getMessage(), e);
            Toast.makeText(this, "Error loading TouchController:\n" + e.getMessage(), Toast.LENGTH_LONG).show();
        }
        try {
            Log.i("ModelActivity", "Loading CollisionController...");
            collisionController = new CollisionController(glView, scene);
            collisionController.addListener(this);
            //touchController.addListener(collisionController);
            //touchController.addListener(scene);
        } catch (Exception e) {
            Log.e("ModelActivity", e.getMessage(), e);
            Toast.makeText(this, "Error loading CollisionController\n" + e.getMessage(), Toast.LENGTH_LONG).show();
        }

        try {
            Log.i("ModelActivity", "Loading CameraController...");
            cameraController = new CameraController(scene.getCamera());
            //glView.getModelRenderer().addListener(cameraController);
            //touchController.addListener(cameraController);
        } catch (Exception e) {
            Log.e("ModelActivity", e.getMessage(), e);
            Toast.makeText(this, "Error loading CameraController" + e.getMessage(), Toast.LENGTH_LONG).show();
        }
        try {
            // TODO: finish UI implementation
            Log.i("ModelActivity", "Loading GUI...");
            gui = new ModelViewerGUI(glView, scene);
            touchController.addListener(gui);
            glView.addListener(gui);
            //去调sufaceview表面添加的东西
            //  scene.addGUIObject(gui);
        } catch (Exception e) {
            Log.e("ModelActivity", e.getMessage(), e);
            Toast.makeText(this, "Error loading GUI" + e.getMessage(), Toast.LENGTH_LONG).show();
        }
        scene.init();
        Log.i("ModelActivity", "Finished loading");
    }

    private void save3dModelResourceToLocal(List<String> datas) {
        //// 发起多个请求
        for (String url : datas) {
            String  fileName = url.substring(url.lastIndexOf('/') + 1);
            File destFile = new File(this.getExternalFilesDir("3dModel").toString(), fileName);
            if(destFile.exists()){
                continue;
            }
            Glide.with(this)
                    .downloadOnly()
                    .load(url)
                    .listener(new RequestListener<File>() {
                        @Override
                        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
                            // Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
                            return false;
                        }

                        @SuppressLint("CheckResult")
                        @Override
                        public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
                            // Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
                            String  fileName = url.substring(url.lastIndexOf('/') + 1);
                            File destFile = new File(ModelActivity.this.getExternalFilesDir("3dModel").toString(), fileName);
                            FileUtils.copy(resource, destFile);
                            // 这里可以执行某些逻辑，如记录日志等
                            counter++;
                            Log.e("file= ",  "url= "+url+" fileName= " + fileName );
                            if(url.contains(".obj")){
                                objName = url.substring(url.lastIndexOf('/') + 1);
                            }else if(url.contains(".mtl")){
                                mtlName = url.substring(url.lastIndexOf('/') + 1);
                            }
                            Log.e("file= ",  "objName= "+objName+" mtlName= " + mtlName +" counter= "+counter);
                            if (counter == datas.size()) { // 所有请求都完成了
                                // 在这里执行处理逻辑
                                // parseMtlmappic(0x0000ff,objName,mtlName);
                                File objFile = new File(ModelActivity.this.getExternalFilesDir("3dModel").toString(),objName);
                                if(objFile.isFile() && objFile.exists()){
                                    Uri uri = Uri.parse("file://" + objFile.getAbsolutePath());
                                    initScene(uri);
                                }
                            }
                            return false;
                        }
                    })
                    .preload();
        }
    }
}