/**
 * @file RoundImage.tsx
 * @description Component that provides functionality to create circular or rounded images
 * in PowerPoint presentations. This tool creates a mask shape that can be used with
 * PowerPoint's built-in shape intersection feature to crop images into a circular shape.
 */

import * as React from "react";
import { CircleRegular } from "@fluentui/react-icons";
import { useStatusContext } from "./App";
import { useCommonStyles } from "./commonStyles";
import ActionButton from "./ActionButton";
import { getErrorMessage, isPictureShape, getFirstSelectedSlide, selectShapesById } from "../types/office-types";

// Configuration constants
const MASK_COLOR = "red";
const SUCCESS_MESSAGE = "Created mask shape. Please select both the image and the oval, then use the 'Shape Format > Merge Shapes > Intersect' command in PowerPoint.";

export const RoundImage: React.FC = () => {
  const styles = useCommonStyles();
  const { setStatusMessage, setStatusType } = useStatusContext();

  /**
   * Validates that an image shape is selected
   * @param shapes The collection of selected shapes
   * @param context The PowerPoint request context
   * @returns The selected image shape or null if validation fails
   */
  const validateShapeSelection = async (
    shapes: PowerPoint.ShapeScopedCollection,
    context: PowerPoint.RequestContext
  ): Promise<PowerPoint.Shape | null> => {
    // Check if any shape is selected
    if (shapes.items.length === 0) {
      setStatusMessage("No shapes are selected. Please select an image.");
      setStatusType("warning");
      return null;
    }
    
    // Get the first selected shape
    const shape = shapes.items[0];
    
    // Load essential properties 
    shape.load(["type"]);
    await context.sync();

    // Ensure the shape is a picture using our type-safe utility
    if (!isPictureShape(shape)) {
      setStatusMessage("Please select an image.");
      setStatusType("warning");
      return null;
    }
    
    return shape;
  };

  /**
   * Creates an elliptical mask shape for the image
   * @param slide The slide to add the mask to
   * @param imageShape The image shape to mask
   * @param context The PowerPoint request context
   * @returns The created mask shape
   */
  const createMaskShape = async (
    slide: PowerPoint.Slide,
    imageShape: PowerPoint.Shape,
    context: PowerPoint.RequestContext
  ): Promise<PowerPoint.Shape> => {
    // Load current dimensions to maintain aspect ratio
    imageShape.load(["width", "height", "left", "top", "id"]);
    await context.sync();
    
    // Create elliptical mask with proper type
    const maskShape = slide.shapes.addGeometricShape(PowerPoint.GeometricShapeType.ellipse);
    
    maskShape.load(["width", "height", "left", "top", "id"]);
    await context.sync();
    
    // Position the mask to match the image
    maskShape.left = imageShape.left;
    
    imageShape.lineFormat.load(["weight"]);
    await context.sync();
    
    maskShape.top = imageShape.top;
    maskShape.width = imageShape.width;
    maskShape.height = imageShape.height;
    
    // Style the mask
    maskShape.fill.setSolidColor(MASK_COLOR);
    maskShape.lineFormat.visible = false;
    
    return maskShape;
  };

  /**
   * Applies the mask to the image and selects both shapes
   * @param slide The slide containing the shapes
   * @param imageShape The image shape to mask
   * @param maskShape The mask shape
   * @param context The PowerPoint request context
   */
  const applyMaskToImage = async (
    slide: PowerPoint.Slide,
    imageShape: PowerPoint.Shape,
    maskShape: PowerPoint.Shape,
    context: PowerPoint.RequestContext
  ): Promise<void> => {
    // Store original dimensions to maintain after selection
    const width = imageShape.width;
    const height = imageShape.height;
    
    // Select both shapes for the user to apply the intersection
    selectShapesById(slide, [imageShape.id, maskShape.id]);
    
    // Ensure we maintain the same size
    imageShape.width = width;
    imageShape.height = height;
    
    await context.sync();
    
    // Update status message with instructions
    setStatusMessage(SUCCESS_MESSAGE);
    setStatusType("warning");
  };

  /**
   * Main function to convert an image to a round image
   */
  const convertToRoundImage = async (): Promise<void> => {
    try {
      await PowerPoint.run(async (context) => {
        // Get the selected shapes
        const shapes = context.presentation.getSelectedShapes();
        shapes.load("items");
        await context.sync();
        
        // Validate selection and get the image shape
        const imageShape = await validateShapeSelection(shapes, context);
        if (!imageShape) {
          return;
        }
        
        // Get the current slide using our type-safe utility
        const slide = getFirstSelectedSlide(context);
        
        // Create the mask shape
        const maskShape = await createMaskShape(slide, imageShape, context);
        
        // Apply the mask and select both shapes
        await applyMaskToImage(slide, imageShape, maskShape, context);
      });
    } catch (error: unknown) {
      const errorMessage = getErrorMessage(error);
      setStatusMessage(`Error: ${errorMessage}`);
      setStatusType("error");
      console.error("Round image error:", error);
    }
  };

  return (
    <div className={styles.container}>
      <div className={styles.buttonGroup}>
        <ActionButton
          title="Round Image"
          icon={<CircleRegular />}
          onClick={convertToRoundImage}
        />
      </div>
    </div>
  );
};

export default RoundImage;
