package com.terrylinla.rnsketchcanvas;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;

import android.graphics.PointF;

import javax.annotation.Nullable;

public class SketchCanvasManager extends SimpleViewManager<SketchCanvas> {
    public static final int COMMAND_ADD_POINT = 1;
    public static final int COMMAND_NEW_PATH = 2;
    public static final int COMMAND_CLEAR = 3;
    public static final int COMMAND_ADD_PATH = 4;
    public static final int COMMAND_DELETE_PATH = 5;
    public static final int COMMAND_SAVE = 6;
    public static final int COMMAND_END_PATH = 7;
    public static final int COMMAND_TO_BASE64 = 8;
    public static final int COMMAND_ADD_TEXT = 9;
    public static final int COMMAND_UPDATE_TEXT = 10;
    public static final int COMMAND_DELETE_TEXT = 11;

    public static SketchCanvas Canvas = null;

    private static final String PROPS_LOCAL_SOURCE_IMAGE = "localSourceImage";
    private static final String PROPS_TEXT = "text";

    @Override
    public String getName() {
        return "RNSketchCanvas";
    }

    @Override
    protected SketchCanvas createViewInstance(ThemedReactContext context) {
        SketchCanvasManager.Canvas = new SketchCanvas(context);
        
        // Register for configuration changes
        context.addLifecycleEventListener(new com.facebook.react.bridge.LifecycleEventListener() {
            @Override
            public void onHostResume() {
                // Check if we need to handle any pending configuration changes
                android.content.res.Configuration config = context.getResources().getConfiguration();
                if (Canvas != null) {
                    onConfigurationChanged(config);
                }
            }

            @Override
            public void onHostPause() {
                // Not needed for orientation changes
            }

            @Override
            public void onHostDestroy() {
                // Clean up resources
                if (Canvas != null) {
                    if (Canvas.mDrawingBitmap != null) {
                        Canvas.mDrawingBitmap.recycle();
                        Canvas.mDrawingBitmap = null;
                    }
                    if (Canvas.mTranslucentDrawingBitmap != null) {
                        Canvas.mTranslucentDrawingBitmap.recycle();
                        Canvas.mTranslucentDrawingBitmap = null;
                    }
                    if (Canvas.mBackgroundImage != null) {
                        Canvas.mBackgroundImage.recycle();
                        Canvas.mBackgroundImage = null;
                    }
                }
            }
        });
        
        return SketchCanvasManager.Canvas;
    }
    
    /**
     * Handle configuration changes
     */
    public void onConfigurationChanged(android.content.res.Configuration newConfig) {
        if (Canvas != null) {
            Canvas.onConfigurationChanged(newConfig);
        }
    }

    @ReactProp(name = PROPS_LOCAL_SOURCE_IMAGE)
    public void setLocalSourceImage(SketchCanvas viewContainer, ReadableMap localSourceImage) {
        if (localSourceImage != null && localSourceImage.getString("filename") != null) {
            viewContainer.openImageFile(
                    localSourceImage.hasKey("filename") ? localSourceImage.getString("filename") : null,
                    localSourceImage.hasKey("directory") ? localSourceImage.getString("directory") : "",
                    localSourceImage.hasKey("mode") ? localSourceImage.getString("mode") : ""
            );
        }
    }

    @ReactProp(name = PROPS_TEXT)
    public void setText(SketchCanvas viewContainer, ReadableArray text) {
        viewContainer.setCanvasText(text);
    }

    @Override
    public Map<String, Integer> getCommandsMap() {
        Map<String, Integer> map = new HashMap<>();

        map.put("addPoint", COMMAND_ADD_POINT);
        map.put("newPath", COMMAND_NEW_PATH);
        map.put("clear", COMMAND_CLEAR);
        map.put("addPath", COMMAND_ADD_PATH);
        map.put("deletePath", COMMAND_DELETE_PATH);
        map.put("save", COMMAND_SAVE);
        map.put("endPath", COMMAND_END_PATH);
        map.put("addText", COMMAND_ADD_TEXT);
        map.put("updateText", COMMAND_UPDATE_TEXT);
        map.put("deleteText", COMMAND_DELETE_TEXT);

        return map;
    }

    @Override
    protected void addEventEmitters(ThemedReactContext reactContext, SketchCanvas view) {
        // Register custom events
    }
    
    @Override
    public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
        Map<String, Object> events = new HashMap<>();
        events.put("onTextTapped", MapBuilder.of("registrationName", "onTextTapped"));
        events.put("onTextDragStart", MapBuilder.of("registrationName", "onTextDragStart"));
        events.put("onTextDragChanged", MapBuilder.of("registrationName", "onTextDragChanged"));
        events.put("onTextDragEnd", MapBuilder.of("registrationName", "onTextDragEnd"));
        events.put("onOrientationChange", MapBuilder.of("registrationName", "onOrientationChange"));
        events.put("onSizeChange", MapBuilder.of("registrationName", "onSizeChange"));
        return events;
    }

    @Override
    public void receiveCommand(SketchCanvas view, String commandType, @Nullable ReadableArray args) {
        receiveCommand(view, Integer.parseInt(commandType), args);
    }

    @Override
    public void receiveCommand(SketchCanvas view, int commandType, @Nullable ReadableArray args) {
        switch (commandType) {
            case COMMAND_ADD_POINT: {
                view.addPoint((float) args.getDouble(0), (float) args.getDouble(1));
                return;
            }
            case COMMAND_NEW_PATH: {
                view.newPath(args.getInt(0), args.getInt(1), (float) args.getDouble(2));
                return;
            }
            case COMMAND_CLEAR: {
                view.clear();
                return;
            }
            case COMMAND_ADD_PATH: {
                ReadableArray path = args.getArray(3);
                ArrayList<PointF> pointPath = new ArrayList<PointF>(path.size());
                for (int i = 0; i < path.size(); i++) {
                    String[] coor = path.getString(i).split(",");
                    pointPath.add(new PointF(Float.parseFloat(coor[0]), Float.parseFloat(coor[1])));
                }
                view.addPath(args.getInt(0), args.getInt(1), (float) args.getDouble(2), pointPath);
                return;
            }
            case COMMAND_DELETE_PATH: {
                view.deletePath(args.getInt(0));
                return;
            }
            case COMMAND_SAVE: {
                view.save(args.getString(0), args.getString(1), args.getString(2), args.getBoolean(3), args.getBoolean(4), args.getBoolean(5), args.getBoolean(6));
                return;
            }
            case COMMAND_END_PATH: {
                view.end();
                return;
            }
            case COMMAND_ADD_TEXT: {
                view.addText(args.getMap(0));
                return;
            }
            case COMMAND_UPDATE_TEXT: {
                view.updateText(args.getMap(0));
                return;
            }
            case COMMAND_DELETE_TEXT: {
                view.deleteText(args.getInt(0));
                return;
            }
            default:
                throw new IllegalArgumentException(String.format(
                        "Unsupported command %d received by %s.",
                        commandType,
                        getClass().getSimpleName()));
        }
    }
}
