import 'websocket-polyfill'
import { SSMClient, GetParameterCommand, PutParameterCommand } from '@aws-sdk/client-ssm'
import { extract } from '@extractus/feed-extractor'
import NDK, { NDKEvent, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk'
import bech32 from 'bech32-buffer'
import moment from 'moment'

const toHexString = nsec => {
    let buffer = bech32.decode(nsec).data
    return buffer.reduce((s, byte) => {
        let hex = byte.toString(16);
        if (hex.length === 1) hex = '0' + hex;
        return s + hex;
    }, '');
}

const htmlToAscii = html => {
    let ascii = html
    ascii = ascii.replaceAll("<p>", "")
    ascii = ascii.replaceAll("</p>", "")
    ascii = ascii.replaceAll("<br>", "")
    ascii = ascii.replaceAll("<img src=\"", "")
    ascii = ascii.replaceAll("\" style=\"max-width:250px;\" />", "")
    return ascii
}
    
export const handler = async (event) => {
    const region = process.env.AWS_REGION || "us-east-1"
    const feed = event.feedUrl
    const nostrNsecParam = event.nostrNsecParam
    const lastRunTimeParam = event.lastRunTimeParam
    const dryrun = event.dryRun

    if (dryrun) {
        console.log("Dry run. Simulating publishes to nostr.")
    }

    let response = {
        totalItems: 0,
        successes: 0,
        errors: []
    }

    const ssmClient = new SSMClient({ region })
    const ssmGetLastRunCommand = new GetParameterCommand({
        Name: lastRunTimeParam
    });

    let since = new Date()
    await ssmClient.send(ssmGetLastRunCommand)
        .then(data => {
            since = data.Parameter.Value
        }).catch(err => {
            console.dir(err)
            response.errors.push(err)
            return response
        })

    const ssmGetNsecCommand = new GetParameterCommand({
        Name: nostrNsecParam,
        WithDecryption: true
    })

    let privkey = ''
    await ssmClient.send(ssmGetNsecCommand)
        .then(data => {
            privkey = toHexString(data.Parameter.Value)
        }).catch(err => {
            console.dir(err)
            response.errors.push(err)
            return response
        })

    if (feed === "") {
        console.dir("feedUrl was not set.")
        return {
            statusCode: 400,
            body: "feedUrl must be provided in payload."
        }
    }

    const ndk = new NDK({
        explicitRelayUrls: [
            "wss://nostr.mom",
            "wss://nostr.snort.social",
            "wss://nostr.lol"
        ]
    })

    await ndk.connect(6000).catch(err => {
        console.dir(err)
        response.errors.push("failed to connect to relay", err)
    })

    const signer = new NDKPrivateKeySigner(privkey)
    ndk.signer = signer

    let rss = await extract(feed, { descriptionMaxLen: 0, normalization: false })
        .catch(err => {
            console.dir(err);
            return response
        })

    let filtered = rss.item.filter(item => moment(item.published).isAfter(since))
    response.totalItems = filtered.length

    for (let item of filtered) {
        let ndkEvent = new NDKEvent(ndk, {
            kind: 1,
            pubkey: ndk.signer.user().hexpubkey,
            content: htmlToAscii(item.description),
            created_at: Math.floor(Date.now() / 1000),
        })

        if (dryrun) {
            response.successes++
            continue
        }

        try {
            await ndkEvent.sign(ndk.signer)
            const published = await ndkEvent.publish()
            if (published) {
                response.successes++
                
                const ssmPutCommand = new PutParameterCommand({
                    Name: lastRunTimeParam,
                    Value: new Date().toISOString(),
                    Type: "String",
                    Overwrite: true
                })
                await ssmClient.send(ssmPutCommand)
                    .catch(err => {
                        console.dir(err)
                        response.errors.push(err)
                        return response
                    })
            }
        } catch(e) {
            console.dir(e)
            response.errors.push(e)
            return response
        }
    }

    return response
}

