package de.danoeh.antennapod.ui.screen.playback;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.text.format.DateFormat;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.ui.common.ThemeUtils;

import java.util.Locale;

public class TimeRangeDialog extends MaterialAlertDialogBuilder {
    private final TimeRangeView view;

    public TimeRangeDialog(@NonNull Context context, int from, int to) {
        super(context);
        view = new TimeRangeView(context, from, to);
        setView(view);
        setPositiveButton(android.R.string.ok, null);
    }

    public int getFrom() {
        return view.from;
    }

    public int getTo() {
        return view.to;
    }

    static class TimeRangeView extends View {
        private static final int DIAL_ALPHA = 120;
        private final Paint paintDial = new Paint();
        private final Paint paintSelected = new Paint();
        private final Paint paintText = new Paint();
        private int from;
        private int to;
        private final RectF bounds = new RectF();
        int touching = 0;

        public TimeRangeView(Context context) { // Used by Android tools
            this(context, 0, 0);
        }

        public TimeRangeView(Context context, int from, int to) {
            super(context);
            this.from = from;
            this.to = to;
            setup();
        }

        private void setup() {
            paintDial.setAntiAlias(true);
            paintDial.setStyle(Paint.Style.STROKE);
            paintDial.setStrokeCap(Paint.Cap.ROUND);
            paintDial.setColor(ThemeUtils.getColorFromAttr(getContext(), android.R.attr.textColorPrimary));
            paintDial.setAlpha(DIAL_ALPHA);

            paintSelected.setAntiAlias(true);
            paintSelected.setStyle(Paint.Style.STROKE);
            paintSelected.setStrokeCap(Paint.Cap.ROUND);
            paintSelected.setColor(ThemeUtils.getColorFromAttr(getContext(), R.attr.colorAccent));

            paintText.setAntiAlias(true);
            paintText.setStyle(Paint.Style.FILL);
            paintText.setColor(ThemeUtils.getColorFromAttr(getContext(), android.R.attr.textColorPrimary));
            paintText.setTextAlign(Paint.Align.CENTER);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
                    && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            } else if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
                super.onMeasure(widthMeasureSpec, widthMeasureSpec);
            } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
                super.onMeasure(heightMeasureSpec, heightMeasureSpec);
            } else if (MeasureSpec.getSize(widthMeasureSpec) < MeasureSpec.getSize(heightMeasureSpec)) {
                super.onMeasure(widthMeasureSpec, widthMeasureSpec);
            } else {
                super.onMeasure(heightMeasureSpec, heightMeasureSpec);
            }
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            float size = getHeight(); // square
            float padding = size * 0.1f;
            paintDial.setStrokeWidth(size * 0.005f);
            bounds.set(padding, padding, size - padding, size - padding);

            paintText.setAlpha(DIAL_ALPHA);
            canvas.drawArc(bounds, 0, 360, false, paintDial);
            for (int i = 0; i < 24; i++) {
                paintDial.setStrokeWidth(size * 0.005f);
                if (i % 6 == 0) {
                    paintDial.setStrokeWidth(size * 0.01f);
                    Point textPos = radToPoint(i / 24.0f * 360.f, size / 2 - 2.5f * padding);
                    paintText.setTextSize(0.4f * padding);
                    canvas.drawText(String.valueOf(i), textPos.x,
                            textPos.y + (-paintText.descent() - paintText.ascent()) / 2, paintText);
                }
                Point outer = radToPoint(i / 24.0f * 360.f, size / 2 - 1.7f * padding);
                Point inner = radToPoint(i / 24.0f * 360.f, size / 2 - 1.9f * padding);
                canvas.drawLine(outer.x, outer.y, inner.x, inner.y, paintDial);
            }
            paintText.setAlpha(255);

            float angleFrom = (float) from / 24 * 360 - 90;
            float angleDistance = (float) ((to - from + 24) % 24) / 24 * 360;
            paintSelected.setStrokeWidth(padding / 6);
            paintSelected.setStyle(Paint.Style.STROKE);
            canvas.drawArc(bounds, angleFrom, angleDistance, false, paintSelected);
            paintSelected.setStyle(Paint.Style.FILL);
            Point p1 = radToPoint(angleFrom + 90, size / 2 - padding);
            canvas.drawCircle(p1.x, p1.y, padding / 2, paintSelected);
            Point p2 = radToPoint(angleFrom + angleDistance + 90, size / 2 - padding);
            canvas.drawCircle(p2.x, p2.y, padding / 2, paintSelected);

            paintText.setTextSize(0.6f * padding);
            String timeRange;
            if (from == to) {
                timeRange = getContext().getString(R.string.sleep_timer_always);
            } else if (DateFormat.is24HourFormat(getContext())) {
                timeRange = String.format(Locale.getDefault(), "%02d:00 - %02d:00", from, to);
            } else {
                timeRange = String.format(Locale.getDefault(), "%02d:00 %s - %02d:00 %s", from % 12,
                        from >= 12 ? "PM" : "AM", to % 12, to >= 12 ? "PM" : "AM");
            }
            canvas.drawText(timeRange, size / 2, (size - paintText.descent() - paintText.ascent()) / 2, paintText);
        }

        protected Point radToPoint(float angle, float radius) {
            return new Point((int) (getWidth() / 2.0 + radius * Math.sin(-angle * Math.PI / 180.0 + Math.PI)),
                    (int) (getHeight() / 2.0 + radius * Math.cos(-angle * Math.PI / 180.0 + Math.PI)));
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            getParent().requestDisallowInterceptTouchEvent(true);
            Point center = new Point(getWidth() / 2, getHeight() / 2);
            double angleRad = Math.atan2(center.y - event.getY(), center.x - event.getX());
            float angle = (float) (angleRad * (180 / Math.PI));
            angle += 360 + 360 - 90;
            angle %= 360;

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                float fromDistance = Math.abs(angle - (float) from / 24 * 360);
                float toDistance = Math.abs(angle - (float) to / 24 * 360);
                if (fromDistance < 15 || fromDistance > (360 - 15)) {
                    touching = 1;
                    return true;
                } else if (toDistance < 15 || toDistance > (360 - 15)) {
                    touching = 2;
                    return true;
                }
            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                int newTime = (int) (24 * (angle / 360.0));
                if (from == to && touching != 0) {
                    // Switch which handle is focussed such that selection is the smaller arc
                    touching = (((newTime - to + 24) % 24) < 12) ? 2 : 1;
                }
                if (touching == 1) {
                    from = newTime;
                    invalidate();
                    return true;
                } else if (touching == 2) {
                    to = newTime;
                    invalidate();
                    return true;
                }
            } else if (touching != 0) {
                touching = 0;
                return true;
            }
            return super.onTouchEvent(event);
        }
    }
}
