/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::cell::Cell;

use dom_struct::dom_struct;
use euclid::default::Size2D;
use pixels::Snapshot;
use webrender_api::ImageKey;

use crate::canvas_context::{
    CanvasContext, CanvasHelpers, HTMLCanvasElementOrOffscreenCanvas,
    LayoutCanvasRenderingContextHelpers,
};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods;
use crate::dom::bindings::codegen::Bindings::ImageBitmapRenderingContextBinding::ImageBitmapRenderingContextMethods;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas as RootedHTMLCanvasElementOrOffscreenCanvas;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{DomRoot, LayoutDom};
use crate::dom::globalscope::GlobalScope;
use crate::dom::imagebitmap::ImageBitmap;
use crate::script_runtime::CanGc;

/// <https://html.spec.whatwg.org/multipage/#imagebitmaprenderingcontext>
#[dom_struct]
pub(crate) struct ImageBitmapRenderingContext {
    reflector_: Reflector,
    /// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-canvas>
    canvas: HTMLCanvasElementOrOffscreenCanvas,
    /// Represents both the [output bitmap] and the [bitmap mode] of the context.
    /// <https://html.spec.whatwg.org/multipage/#concept-imagebitmaprenderingcontext-output-bitmap>
    /// <https://html.spec.whatwg.org/multipage/#concept-imagebitmaprenderingcontext-bitmap-mode>
    #[no_trace]
    bitmap: DomRefCell<Option<Snapshot>>,
    origin_clean: Cell<bool>,
}

impl ImageBitmapRenderingContext {
    /// <https://html.spec.whatwg.org/multipage/#imagebitmaprenderingcontext-creation-algorithm>
    #[cfg_attr(crown, allow(crown::unrooted_must_root))]
    fn new_inherited(canvas: HTMLCanvasElementOrOffscreenCanvas) -> ImageBitmapRenderingContext {
        ImageBitmapRenderingContext {
            reflector_: Reflector::new(),
            canvas,
            bitmap: DomRefCell::new(None),
            origin_clean: Cell::new(true),
        }
    }

    pub(crate) fn new(
        global: &GlobalScope,
        canvas: &RootedHTMLCanvasElementOrOffscreenCanvas,
        can_gc: CanGc,
    ) -> DomRoot<ImageBitmapRenderingContext> {
        reflect_dom_object(
            Box::new(ImageBitmapRenderingContext::new_inherited(
                HTMLCanvasElementOrOffscreenCanvas::from(canvas),
            )),
            global,
            can_gc,
        )
    }

    /// <https://html.spec.whatwg.org/multipage/#set-an-imagebitmaprenderingcontext's-output-bitmap>
    fn set_bitmap(&self, image_bitmap: Option<&ImageBitmap>) {
        match image_bitmap {
            Some(image_bitmap) => {
                // Step 2.1. Set context's bitmap mode to valid.
                // Step 2.2. Set context's output bitmap to refer to the same
                // underlying bitmap data as bitmap, without making a copy.
                *self.bitmap.borrow_mut() = image_bitmap.bitmap_data().clone();

                // The origin-clean flag of bitmap is included in the bitmap
                // data to be referenced by context's output bitmap.
                self.origin_clean.set(image_bitmap.origin_is_clean());
            },
            None => {
                // Step 1.1. Set context's bitmap mode to blank.
                // Step 1.2. Let canvas be the canvas element to which context is bound.
                // Step 1.3. Set context's output bitmap to be transparent black
                // with a natural width equal to the numeric value of canvas's
                // width attribute and a natural height equal to the numeric
                // value of canvas's height attribute, those values being
                // interpreted in CSS pixels.
                *self.bitmap.borrow_mut() = None;

                // Step 1.4. Set the output bitmap's origin-clean flag to true.
                self.origin_clean.set(true);
            },
        }
    }
}

impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, ImageBitmapRenderingContext> {
    fn canvas_data_source(self) -> Option<ImageKey> {
        None
    }
}

impl CanvasContext for ImageBitmapRenderingContext {
    type ID = ();

    fn context_id(&self) -> Self::ID {}

    fn canvas(&self) -> Option<RootedHTMLCanvasElementOrOffscreenCanvas> {
        Some(RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas))
    }

    /// <https://html.spec.whatwg.org/multipage/#the-canvas-element:concept-canvas-bitmaprenderer>
    fn resize(&self) {
        // The absence of the bitmap is the context's blank bitmap mode so the
        // steps to set output bitmap could be omitted.
    }

    fn reset_bitmap(&self) {
        // The newly created bitmap should be of the same dimensions as the
        // previous bitmap if the context's bitmap mode is valid.
        if self.bitmap.borrow().is_none() {
            return;
        }

        let size = self.bitmap.borrow().as_ref().unwrap().size();
        *self.bitmap.borrow_mut() = Some(Snapshot::cleared(size));
    }

    fn get_image_data(&self) -> Option<Snapshot> {
        match self.bitmap.borrow().as_ref() {
            Some(bitmap) => Some(bitmap.clone()),
            None => {
                let size = self.canvas.size();
                if size.is_empty() ||
                    pixels::compute_rgba8_byte_length_if_within_limit(
                        size.width as usize,
                        size.height as usize,
                    )
                    .is_none()
                {
                    None
                } else {
                    Some(Snapshot::cleared(size))
                }
            },
        }
    }

    fn origin_is_clean(&self) -> bool {
        self.origin_clean.get()
    }

    fn size(&self) -> Size2D<u32> {
        self.bitmap
            .borrow()
            .as_ref()
            .map_or_else(|| self.canvas.size(), |bitmap| bitmap.size())
    }

    fn image_key(&self) -> Option<ImageKey> {
        None
    }
}

impl ImageBitmapRenderingContextMethods<crate::DomTypeHolder> for ImageBitmapRenderingContext {
    /// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-canvas>
    fn Canvas(&self) -> RootedHTMLCanvasElementOrOffscreenCanvas {
        RootedHTMLCanvasElementOrOffscreenCanvas::from(&self.canvas)
    }

    /// <https://html.spec.whatwg.org/multipage/#dom-imagebitmaprenderingcontext-transferfromimagebitmap>
    fn TransferFromImageBitmap(&self, image_bitmap: Option<&ImageBitmap>) -> Fallible<()> {
        let Some(image_bitmap) = image_bitmap else {
            // Step 2. If bitmap is null, then run the steps to set an
            // ImageBitmapRenderingContext's output bitmap, with
            // bitmapContext as the context argument and no bitmap argument,
            // then return.
            self.set_bitmap(None);

            return Ok(());
        };

        // Step 3. If the value of bitmap's [[Detached]] internal slot
        // is set to true, then throw an "InvalidStateError"
        // DOMException.
        if image_bitmap.is_detached() {
            return Err(Error::InvalidState);
        }

        // Step 4. Run the steps to set an ImageBitmapRenderingContext's
        // output bitmap, with the context argument equal to
        // bitmapContext, and the bitmap argument referring to bitmap's
        // underlying bitmap data.
        self.set_bitmap(Some(image_bitmap));

        // Step 5. Set the value of bitmap's [[Detached]] internal slot
        // to true.
        // Step 6. Unset bitmap's bitmap data.
        image_bitmap.Close();

        Ok(())
    }
}
