using Gee;
using Gtk;

private class SizeCache 
{
    private static SizeCache instance = null;
    private HashMap<string, Graphene.Size?> size_cache = new HashMap<string, Graphene.Size?>();

    public static SizeCache get_instance() {
        if (instance == null) {
            instance = new SizeCache();
        }
        return instance;
    }

    public Graphene.Size? get_size(string image_path) {
        return size_cache.get(image_path);
    }

    public void set_size(string image_path, Graphene.Size size) {
        size_cache.set(image_path, size);
    }
}

private class ImageBubbleLayout : BubbleLayout
{
    public string image_path;
    public bool is_downloaded;
    public string? attachment_guid;

    private Graphene.Size image_size;
    private Gdk.Texture? cached_texture = null;

    public ImageBubbleLayout(string image_path, bool from_me, Widget parent, float max_width, Graphene.Size? image_size = null) {
        base(parent, max_width);
        
        this.from_me = from_me;
        this.image_path = image_path;
        this.is_downloaded = false;

        // Calculate image dimensions for layout
        calculate_image_dimensions(image_size);
    }

    private void calculate_image_dimensions(Graphene.Size? image_size) {
        if (image_size != null) {
            this.image_size = image_size;
            return;
        }

        var cached_size = SizeCache.get_instance().get_size(image_path);
        if (cached_size != null) {
            this.image_size = cached_size;
            return;
        }

        // Try to load the image to get its dimensions
        try {
            warning("No image size provided, loading image to get dimensions");
            
            var texture = Gdk.Texture.from_filename(image_path);
            var original_width = (float)texture.get_width();
            var original_height = (float)texture.get_height();
            
            this.image_size = Graphene.Size() { width = original_width, height = original_height };
            SizeCache.get_instance().set_size(image_path, this.image_size);
        } catch (Error e) {
            // Fallback dimensions if image can't be loaded
            warning("Failed to load image %s: %s", image_path, e.message);
            this.image_size = Graphene.Size() { width = 200.0f, height = 150.0f };
        }
    }

    private void load_image_if_needed() {
        if (cached_texture != null) {
            return;
        }

        if (!is_downloaded) {
            return;
        }

        try {
            cached_texture = Gdk.Texture.from_filename(image_path);
        } catch (Error e) {
            warning("Failed to load image %s: %s", image_path, e.message);
        }
    }

    private float intrinsic_height {
        get {
            var scale_factor = float.min(max_width / image_size.width, 1.0f);
            return image_size.height * scale_factor;
        }
    }

    private float intrinsic_width {
        get {
            var scale_factor = float.min(max_width / image_size.width, 1.0f);
            return image_size.width * scale_factor;
        }
    }

    public override float get_height() {
        return float.max(intrinsic_height, 100.0f);
    }

    public override float get_width() {
        return float.max(intrinsic_width, 200.0f);
    }

    public override void draw_content(Snapshot snapshot) {
        load_image_if_needed();

        snapshot.save();

        var image_rect = Graphene.Rect () {
            origin = Graphene.Point() { x = 0, y = 0 },
            size = Graphene.Size() { width = intrinsic_width, height = intrinsic_height }
        };

        // Center image in the bubble (if it's smaller than the bubble)
        snapshot.translate(Graphene.Point() { 
            x = (get_width() - intrinsic_width) / 2, 
            y = (get_height() - intrinsic_height) / 2 
        });

        if (cached_texture != null) {
            snapshot.append_texture(cached_texture, image_rect);
        } else {
            snapshot.append_color(Gdk.RGBA() { red = 0.6f, green = 0.6f, blue = 0.6f, alpha = 0.5f }, image_rect);
        }

        snapshot.restore();
    }

    public override void copy(Gdk.Clipboard clipboard) {
        clipboard.set_texture(cached_texture);
    }
} 