//
//  MessageRowCard.swift
//  lichunWebsocket
//
//  Individual message row card for messages list
//

import SwiftUI

struct MessageRowCard: View {
    @EnvironmentObject var webSocketService: WebSocketService
    let person: Person

    @State private var isPressed = false

    // MARK: - Computed Properties

    /// Last conversation with this person
    private var conversation: ConversationObj? {
        webSocketService.player.activeConversations.first(where: { $0.character == person.id })
    }

    /// Most recent message by datetime (not array position)
    private var lastMessage: ConversationMessage? {
        conversation?.mostRecentMessage
    }

    /// Last message text
    private var lastMessageText: String {
        lastMessage?.message ?? "No recent messages"
    }

    /// Last message preview (truncated)
    private var lastMessagePreview: String {
        if lastMessageText.count > 60 {
            return String(lastMessageText.prefix(60)) + "..."
        }
        return lastMessageText
    }

    /// Is the last message from the player?
    private var isLastMessageFromPlayer: Bool {
        guard let msg = lastMessage else { return false }
        return msg.sender == webSocketService.person.id
    }

    /// Is this conversation unread?
    private var isUnread: Bool {
        conversation?.unread ?? false
    }

    /// Formatted elapsed time SINCE the last message, measured in IN-GAME time.
    ///
    /// The server stamps `msg.datetime` with the real wall clock, but it also
    /// records the simulated game clock at send time in `msg.date` (yyyy-MM-dd)
    /// and `msg.time` (HH:mm). The current game clock lives on the player
    /// (`player.date` + `hourOfDay`/`minuteOfHour`). Comparing those two game
    /// timestamps yields elapsed *game* time, not real-world elapsed time.
    private var timeAgo: String {
        guard let msg = lastMessage else { return "" }

        guard let messageGameDate = gameDate(date: msg.date, time: msg.time),
              let nowGameDate = currentGameDate() else {
            // Game clock unavailable (e.g. malformed/partial date) — fall back
            // to the raw game time-of-day rather than a real-world "X ago".
            return msg.time
        }

        // Clamp clock skew (message stamped slightly ahead of "now") to 0.
        let interval = max(0, nowGameDate.timeIntervalSince(messageGameDate))

        if interval < 60 {
            return "Just now"
        } else if interval < 3600 {
            let minutes = Int(interval / 60)
            return "\(minutes)m ago"
        } else if interval < 86400 {
            let hours = Int(interval / 3600)
            return "\(hours)h ago"
        } else if interval < 172800 {
            return "Yesterday"
        } else {
            let days = Int(interval / 86400)
            return "\(days)d ago"
        }
    }

    /// UTC calendar so plain date/time strings compare without timezone drift.
    private static let gameCalendar: Calendar = {
        var cal = Calendar(identifier: .gregorian)
        cal.timeZone = TimeZone(identifier: "UTC") ?? .current
        return cal
    }()

    /// Build a `Date` from a game date ("yyyy-MM-dd") and time ("HH:mm").
    /// Returns nil unless a full year-month-day date is present.
    private func gameDate(date: String, time: String) -> Date? {
        let dateParts = date.split(separator: "-")
        guard dateParts.count == 3,
              let year = Int(dateParts[0]),
              let month = Int(dateParts[1]),
              let day = Int(dateParts[2]) else {
            return nil
        }

        let timeParts = time.split(separator: ":")
        let hour = timeParts.count >= 1 ? Int(timeParts[0]) ?? 0 : 0
        let minute = timeParts.count >= 2 ? Int(timeParts[1]) ?? 0 : 0

        var components = DateComponents()
        components.year = year
        components.month = month
        components.day = day
        components.hour = hour
        components.minute = minute
        return Self.gameCalendar.date(from: components)
    }

    /// The current game clock as a `Date`, from the player's simulated time.
    private func currentGameDate() -> Date? {
        let player = webSocketService.player
        let hh = String(format: "%02d:%02d", player.hourOfDay, player.minuteOfHour)
        return gameDate(date: player.date, time: hh)
    }

    /// Primary relationship type
    private var primaryRelationship: String {
        person.relationships.first?.replacingOccurrences(of: "_", with: " ").capitalized ?? "Acquaintance"
    }

    /// Affinity color
    private var affinityColor: Color {
        if person.affinity >= 80 {
            return AppColors.loveInterest
        } else if person.affinity >= 60 {
            return AppColors.friend
        } else if person.affinity >= 40 {
            return AppColors.family
        } else {
            return AppColors.secondaryText
        }
    }

    // MARK: - Body

    var body: some View {
        BaseCard(
            backgroundColor: AppColors.surfaceElevated,
            borderColor: AppColors.primary.opacity(0.08),
            showShadow: true,
            enableAnimation: false
        ) {
            HStack(spacing: AppSpacing.md) {
                // Avatar with warm gradient border
                ZStack {
                    Circle()
                        .fill(
                            LinearGradient(
                                colors: [
                                    affinityColor.opacity(0.25),
                                    AppColors.accent.opacity(0.25)
                                ],
                                startPoint: .topLeading,
                                endPoint: .bottomTrailing
                            )
                        )
                        .frame(width: 66, height: 66)
                        .shadow(
                            color: affinityColor.opacity(0.15),
                            radius: 6,
                            x: 0,
                            y: 2
                        )

                    CharacterAvatar(
                        person: person,
                        size: 60,
                        showBorder: false,
                        showGlow: false
                    )
                }

                // Message content
                VStack(alignment: .leading, spacing: 6) {
                    // Name and affinity
                    HStack(spacing: 6) {
                        Text("\(person.firstname) \(person.lastname)")
                            .font(.appHeadline)
                            .foregroundColor(AppColors.primaryText)
                            .lineLimit(1)

                        Spacer()

                        // Affinity indicator
                        HStack(spacing: 2) {
                            Image(systemName: "heart.fill")
                                .font(.system(size: 11))
                                .foregroundColor(affinityColor)
                            Text("\(person.affinity)")
                                .font(.appCaption)
                                .foregroundColor(affinityColor)
                        }
                    }

                    // Relationship badge
                    RelationshipBadge(relationship: primaryRelationship)

                    // Last message preview
                    HStack(alignment: .top, spacing: 4) {
                        if isLastMessageFromPlayer {
                            Text("You:")
                                .font(.appCaption)
                                .foregroundColor(AppColors.primary)
                        }

                        Text(lastMessagePreview)
                            .font(.appCaption)
                            .foregroundColor(AppColors.secondaryText)
                            .lineLimit(2)
                            .multilineTextAlignment(.leading)
                    }

                    // Time and unread indicator
                    HStack(spacing: 6) {
                        Text(timeAgo)
                            .font(.appSmall)
                            .foregroundColor(AppColors.disabledText)

                        if isUnread {
                            Circle()
                                .fill(AppColors.primary)
                                .frame(width: 10, height: 10)
                        }
                    }
                }

                // Chevron
                Image(systemName: "chevron.right")
                    .font(.system(size: 14, weight: .semibold))
                    .foregroundColor(AppColors.secondaryText)
            }
        }
        .scaleEffect(isPressed ? 0.98 : 1.0)
        .animation(.spring(response: 0.3, dampingFraction: 0.7), value: isPressed)
    }
}

// MARK: - Preview
#Preview {
    PreviewContainer()
}

private struct PreviewContainer: View {
    @StateObject private var service = WebSocketService(urlSession: URLSession.shared, delegateQueue: OperationQueue())

    var body: some View {
        let person = makeMockPerson()

        VStack(spacing: AppSpacing.md) {
            MessageRowCard(person: person)
        }
        .environmentObject(service)
        .padding()
        .background(AppColors.background)
    }

    private func makeMockPerson() -> Person {
        let person = Person()
        person.id = "1"
        person.firstname = "Emma"
        person.lastname = "Chen"
        person.image = "https://api.dicebear.com/7.x/avataaars/svg?seed=Emma"
        person.affinity = 75
        person.relationships = ["friend", "colleague"]

        // Setup mock conversation with JSON decoding
        let json = """
        {
            "id": "conv1",
            "cType": "casual",
            "character": "1",
            "conversation": [{
                "id": "msg1",
                "message": "Hey! How have you been? I was thinking we should grab coffee sometime.",
                "sentiment": "positive",
                "sender": "1",
                "datetime": "2025-11-12 14:30:00.000000",
                "date": "2025-11-12",
                "time": "14:30"
            }],
            "question": 0
        }
        """

        if let data = json.data(using: .utf8),
           let conversation = try? JSONDecoder().decode(ConversationObj.self, from: data) {
            service.player.activeConversations = [conversation]
        }

        service.player.r = [person]
        return person
    }
}
