import SwiftUI

// MARK: - PhotoCollageView

/// Telegram-style photo collage layout for 1–5 image attachments.
///
/// Patterns:
/// - 1 photo: full width, aspect ratio preserved
/// - 2 photos: side by side, equal width, same height
/// - 3 photos: large left (2/3) + two stacked right (1/3)
/// - 4 photos: 2×2 grid
/// - 5 photos: 2 top + 3 bottom
///
/// A thin `borderWidth` padding lets the parent bubble's background color
/// show through as a colored border around the images (Telegram-style).
/// Inner corners match the outer `MessageBubbleShape` radii minus `borderWidth`.
struct PhotoCollageView: View {

    let attachments: [MessageAttachment]
    let message: ChatMessage
    let outgoing: Bool
    let maxWidth: CGFloat
    let position: BubblePosition

    /// Called when user taps a loaded image.
    var onImageTap: ((UIImage) -> Void)?

    /// Padding between images and bubble edge — bubble background shows through.
    private let borderWidth: CGFloat = 2

    /// Gap between images in a multi-image grid.
    private let spacing: CGFloat = 2

    /// Bubble fill color — used as gap color between collage cells.
    private var bubbleColor: Color {
        outgoing ? RosettaColors.figmaBlue : RosettaColors.Adaptive.messageBubble
    }

    /// Maximum collage height.
    private let maxCollageHeight: CGFloat = 320

    var body: some View {
        let contentWidth = maxWidth - borderWidth * 2

        collageContent(contentWidth: contentWidth)
            .clipShape(InnerBubbleClipShape(position: position, outgoing: outgoing, inset: borderWidth))
            .padding(borderWidth)
    }

    // MARK: - Content Router

    @ViewBuilder
    private func collageContent(contentWidth: CGFloat) -> some View {
        switch attachments.count {
        case 0:
            EmptyView()
        case 1:
            singleImage(contentWidth: contentWidth)
        case 2:
            twoImages(contentWidth: contentWidth)
        case 3:
            threeImages(contentWidth: contentWidth)
        case 4:
            fourImages(contentWidth: contentWidth)
        default:
            fiveImages(contentWidth: contentWidth)
        }
    }

    // MARK: - 1 Photo: Full Width

    private func singleImage(contentWidth: CGFloat) -> some View {
        MessageImageView(
            attachment: attachments[0],
            message: message,
            outgoing: outgoing,
            maxWidth: contentWidth,
            onImageTap: onImageTap
        )
    }

    // MARK: - 2 Photos: Side by Side

    private func twoImages(contentWidth: CGFloat) -> some View {
        let cellWidth = (contentWidth - spacing) / 2
        let cellHeight = min(cellWidth * 1.2, maxCollageHeight)

        return HStack(spacing: spacing) {
            collageCell(attachments[0], width: cellWidth, height: cellHeight)
            collageCell(attachments[1], width: cellWidth, height: cellHeight)
        }
        .frame(width: contentWidth, height: cellHeight)
        .background(bubbleColor)
    }

    // MARK: - 3 Photos: 1 Large Left + 2 Stacked Right

    private func threeImages(contentWidth: CGFloat) -> some View {
        let rightWidth = contentWidth * 0.34
        let leftWidth = contentWidth - spacing - rightWidth
        let totalHeight = min(leftWidth * 1.1, maxCollageHeight)
        let rightCellHeight = (totalHeight - spacing) / 2

        return HStack(spacing: spacing) {
            collageCell(attachments[0], width: leftWidth, height: totalHeight)
            VStack(spacing: spacing) {
                collageCell(attachments[1], width: rightWidth, height: rightCellHeight)
                collageCell(attachments[2], width: rightWidth, height: rightCellHeight)
            }
        }
        .frame(width: contentWidth, height: totalHeight)
        .background(bubbleColor)
    }

    // MARK: - 4 Photos: 2×2 Grid

    private func fourImages(contentWidth: CGFloat) -> some View {
        let cellWidth = (contentWidth - spacing) / 2
        let cellHeight = min(cellWidth * 0.85, maxCollageHeight / 2)
        let totalHeight = cellHeight * 2 + spacing

        return VStack(spacing: spacing) {
            HStack(spacing: spacing) {
                collageCell(attachments[0], width: cellWidth, height: cellHeight)
                collageCell(attachments[1], width: cellWidth, height: cellHeight)
            }
            HStack(spacing: spacing) {
                collageCell(attachments[2], width: cellWidth, height: cellHeight)
                collageCell(attachments[3], width: cellWidth, height: cellHeight)
            }
        }
        .frame(width: contentWidth, height: totalHeight)
        .background(bubbleColor)
    }

    // MARK: - 5 Photos: 2 Top + 3 Bottom

    private func fiveImages(contentWidth: CGFloat) -> some View {
        let topCellWidth = (contentWidth - spacing) / 2
        let bottomCellWidth = (contentWidth - spacing * 2) / 3
        let topHeight = min(topCellWidth * 0.85, maxCollageHeight * 0.55)
        let bottomHeight = min(bottomCellWidth * 0.85, maxCollageHeight * 0.45)
        let totalHeight = topHeight + spacing + bottomHeight

        return VStack(spacing: spacing) {
            HStack(spacing: spacing) {
                collageCell(attachments[0], width: topCellWidth, height: topHeight)
                collageCell(attachments[1], width: topCellWidth, height: topHeight)
            }
            HStack(spacing: spacing) {
                collageCell(attachments[2], width: bottomCellWidth, height: bottomHeight)
                collageCell(attachments[3], width: bottomCellWidth, height: bottomHeight)
                collageCell(attachments[4], width: bottomCellWidth, height: bottomHeight)
            }
        }
        .frame(width: contentWidth, height: totalHeight)
        .background(bubbleColor)
    }

    // MARK: - Collage Cell

    @ViewBuilder
    private func collageCell(
        _ attachment: MessageAttachment,
        width: CGFloat,
        height: CGFloat
    ) -> some View {
        MessageImageView(
            attachment: attachment,
            message: message,
            outgoing: outgoing,
            collageSize: CGSize(width: width, height: height),
            maxWidth: width,
            onImageTap: onImageTap
        )
        .frame(width: width, height: height)
        .clipped()
    }
}

// MARK: - Inner Bubble Clip Shape

/// Rounded rect that mirrors `MessageBubbleShape` corner radii but inset by `inset`.
/// Used to clip images inside the bubble so the border gap has matching corners.
struct InnerBubbleClipShape: Shape {
    let position: BubblePosition
    let outgoing: Bool
    let inset: CGFloat

    func path(in rect: CGRect) -> Path {
        let r: CGFloat = max(18 - inset, 0)
        let s: CGFloat = max(8 - inset, 0)
        let (tl, tr, bl, br) = cornerRadii(r: r, s: s)

        let maxR = min(rect.width, rect.height) / 2
        let cTL = min(tl, maxR)
        let cTR = min(tr, maxR)
        let cBL = min(bl, maxR)
        let cBR = min(br, maxR)

        var p = Path()
        p.move(to: CGPoint(x: rect.minX + cTL, y: rect.minY))

        p.addLine(to: CGPoint(x: rect.maxX - cTR, y: rect.minY))
        p.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.minY),
                 tangent2End: CGPoint(x: rect.maxX, y: rect.minY + cTR),
                 radius: cTR)

        p.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cBR))
        p.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY),
                 tangent2End: CGPoint(x: rect.maxX - cBR, y: rect.maxY),
                 radius: cBR)

        p.addLine(to: CGPoint(x: rect.minX + cBL, y: rect.maxY))
        p.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.maxY),
                 tangent2End: CGPoint(x: rect.minX, y: rect.maxY - cBL),
                 radius: cBL)

        p.addLine(to: CGPoint(x: rect.minX, y: rect.minY + cTL))
        p.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY),
                 tangent2End: CGPoint(x: rect.minX + cTL, y: rect.minY),
                 radius: cTL)

        p.closeSubpath()
        return p
    }

    /// Same logic as `MessageBubbleShape.cornerRadii` but with inset-adjusted radii.
    private func cornerRadii(r: CGFloat, s: CGFloat)
        -> (topLeading: CGFloat, topTrailing: CGFloat,
            bottomLeading: CGFloat, bottomTrailing: CGFloat) {
        switch position {
        case .single:
            return (r, r, r, r)
        case .top:
            return outgoing ? (r, r, r, s) : (r, r, s, r)
        case .mid:
            return outgoing ? (r, s, r, s) : (s, r, s, r)
        case .bottom:
            return outgoing ? (r, s, r, r) : (s, r, r, r)
        }
    }
}
