--[[
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
]]--

-- This is thread.lua - a script for fetching a thread based on a message
-- that is in said thread.

local JSON = require 'cjson'
local elastic = require 'lib/elastic'
local aaa = require 'lib/aaa'
local user = require 'lib/user'
local cross = require 'lib/cross'
local config = require 'lib/config'
local utils = require 'lib/utils'

local emls_thrd

-- func that fetches all children of an original topic email thingy
local function fetchChildren(r, pdoc, c, biglist, account)
    c = (c or 0) + 1
    -- don't fetch more than 250 subtrees, we don't want to nest ad nauseam
    if c > 250 then
        return {}
    end
    -- biglist is for making sure we dont' fetch something twice
    biglist = biglist or {}
    local children = {}
    -- find any emails that reference this one
    local emid = r:escape(pdoc['message-id'])
    local docs = elastic.findFast( ('in-reply-to:"%s" OR references:"%s"'):format(emid, emid), 50, "mbox")
    for k, doc in pairs(docs) do
        -- if we haven't seen this email before, check for its kids and add it to the bunch
        if (not biglist[doc['message-id']]) and aaa.canAccessDoc(r, doc, account) then
            biglist[doc['message-id']] = true
            local mykids = fetchChildren(r, doc, c, biglist, account)
            if not account and config.antispam then
                doc = utils.anonymizeHdrs(doc)
            end
            local dc = {
                tid = doc.mid,
                mid = doc.mid,
                subject = doc.subject,
                from = doc.from,
                id = doc.request_id,
                epoch = doc.epoch,
                children = mykids,
                irt = doc['in-reply-to']
            }
            table.insert(children, dc)
            table.insert(emls_thrd, dc)
        else
            biglist[doc['message-id']] = true
            docs[k] = nil
        end
    end
    return children
end

function handle(r)
    cross.contentType(r, "application/json; charset=UTF-8")
    local DEBUG = config.debug or false
    local START = DEBUG and r:clock() or nil
    local get = r:parseargs()
    -- get the parameter (if any) and tidy it up
    local eid = (get.id or ""):gsub("\"", "")
    -- If it is the empty string then set it to "1" so ES doesn't barf
    -- N.B. ?id is treated as ?id=1
    if #eid == 0 then eid = "1" end
    local doc = elastic.get("mbox", eid, true)
    emls_thrd = {}
    -- Try searching by mid if not found, for backward compat
    if not doc or not doc.mid then
        local docs = elastic.find("message-id:\"" .. r:escape(eid) .. "\"", 1, "mbox")
        if #docs == 0 and #eid == utils.SHORTENED_LINK_LEN then
            docs = elastic.find("mid:" .. r:escape(eid) .. "*", 1, "mbox")
        end
        if #docs == 1 then
            doc = docs[1]
        end
    end
    if get.timetravel then
        doc = utils.findParent(r, doc, elastic)
    end
    local doclist = {}
    
    -- did we find an email?
    if doc then
        local account = user.get(r)
        if doc and doc.mid and aaa.canAccessDoc(r, doc, account) then
            if not account and config.antispam then
                doc = utils.anonymizeHdrs(doc)
            end
            table.insert(emls_thrd, doc)
            doc.children = fetchChildren(r, doc, 1, nil, account)
            doc.tid = doc.mid
            doc.id = doc.request_id
            --doc.body = nil
            r:puts(JSON.encode({
                took = DEBUG and (r:clock() - START) or nil,
                emails = emls_thrd,
            }))
            return cross.OK
        end
    end
    r:puts(JSON.encode{error = "No such e-mail or you do not have access to it."})
    return cross.OK
end

cross.start(handle)
