import { GROUP_NAME_MAX_LENGTH } from '@/lib/groups/groupSettings'
import { parseOptionalImageDataUrl } from '@/lib/media/parseImageDataUrl'
import { isGroupLeaderRole } from '@/lib/groups/groupMemberRole'
import type { getDb } from '@/server/db'

type AppDb = Awaited<ReturnType<typeof getDb>>

export type UpdateGroupByLeaderInput = {
    name?: unknown
    isCanApplicapplication?: unknown
    avatarUrl?: unknown
    bannerUrl?: unknown
    removeBanner?: unknown
}

export class UpdateGroupError extends Error {
    code: string

    constructor(code: string, message: string) {
        super(message)
        this.code = code
        this.name = 'UpdateGroupError'
    }
}

export async function assertGroupLeader(
    db: AppDb,
    groupId: string,
    userId: string
): Promise<void> {
    const row = await db.get<{ role: string }>(
        `SELECT role FROM user_groups WHERE group_id = ? AND user_id = ?`,
        [groupId, userId]
    )
    if (!row || !isGroupLeaderRole(row.role)) {
        throw new UpdateGroupError('FORBIDDEN', 'Only the family leader can update settings')
    }
}

export async function updateGroupByLeader(
    db: AppDb,
    groupId: string,
    input: UpdateGroupByLeaderInput
): Promise<void> {
    const sets: string[] = []
    const values: unknown[] = []

    if (input.name !== undefined) {
        const name = String(input.name ?? '').trim()
        if (!name) {
            throw new UpdateGroupError('INVALID_NAME', 'Family name is required')
        }
        if (name.length > GROUP_NAME_MAX_LENGTH) {
            throw new UpdateGroupError('INVALID_NAME', 'Family name is too long')
        }
        sets.push('name = ?')
        values.push(name)
    }

    if (input.isCanApplicapplication !== undefined) {
        sets.push('is_can_application = ?')
        values.push(input.isCanApplicapplication ? 1 : 0)
    }

    const avatarParsed = parseOptionalImageDataUrl(input.avatarUrl)
    if (!avatarParsed.ok) {
        throw new UpdateGroupError('INVALID_AVATAR', 'Invalid avatar image')
    }
    if ('value' in avatarParsed) {
        sets.push('avatar_url = ?')
        values.push(avatarParsed.value)
    }

    const bannerParsed = parseOptionalImageDataUrl(input.bannerUrl)
    if (!bannerParsed.ok) {
        throw new UpdateGroupError('INVALID_BANNER', 'Invalid cover image')
    }
    if ('value' in bannerParsed) {
        sets.push('banner_url = ?')
        values.push(bannerParsed.value)
    } else if (input.removeBanner === true) {
        sets.push('banner_url = ?')
        values.push(null)
    }

    if (sets.length === 0) {
        throw new UpdateGroupError('NO_CHANGES', 'No fields to update')
    }

    sets.push(`updated_at = CAST(strftime('%s','now') AS INTEGER)`)
    values.push(groupId)

    const result = await db.run(
        `UPDATE groups SET ${sets.join(', ')} WHERE group_id = ?`,
        values
    )
    if ((result.changes ?? 0) < 1) {
        throw new UpdateGroupError('NOT_FOUND', 'Group not found')
    }
}
