package alraune.back

import alraune.back.Al.*
import alraune.back.AlTag.*
import alraune.back.EntityPageTemplate.Identification
import vgrechka.*
import alraune.back.Col.*
import java.util.function.Supplier

@Suppress("unused")
class SpitOrderPage : SpitPage {
    val spit = MakeOrderPageShit().dance().spitPage!!
    override fun spit() = spit.spit()
    override fun isPrivate() = spit.isPrivate
}

class MakeOrderPageShit {
    val filesTabID = "Files"

    var pedro by notNull<EntityPageTemplate.Pedro<AlUAOrder>>()

    fun dance(): EntityPageTemplate.Product {
        val t = EntityPageTemplate1<AlUAOrder>()

        pedro = object : EntityPageTemplate.Pedro<AlUAOrder>() {
            override fun identification() = Identification.ExplicitOrSearch
            override fun entityClass() = AlUAOrder::class.java

            override fun impersonationMakesSense(impersonateAs: AlUserKind) = when (impersonateAs) {
                AlUserKind.Customer -> true
                AlUserKind.Admin -> true
                AlUserKind.Writer -> Al2.isWriterAssigned(pedro.juan.entity)
            }

            override fun pageClass() = SpitOrderPage::class.java

            override fun applicableEntityAddressings() = when {
                rctx().isAdmin -> mutableListOf()
                else -> mutableListOf<EntityAddressing<AlUAOrder>>()
            }

            override fun getTable() = "ua_orders"

            override fun getNoEntityWithIDMessage() = t("TOTE", "Заказа с ID <b>%s</b> не существует, такие дела...")
            override fun getNoEntityWithUUIDMessage() = t("TOTE", "Заказа с UUID <b>%s</b> не существует, такие дела...")
            override fun getNoPermissionsForEntityWithIDMessage() = t("TOTE", "К заказу с ID <b>%s</b> у тебя доступа нет, приятель")

            override fun paramsModalContent(): EntityPageTemplate.ParamsModalContent {
                return EntityPageTemplate.ParamsModalContent {frc2, fields ->
                    OrderPile2.renderOrderParamsFormBody(frc2, fields)
                }
            }

            override fun updateEntityParams(fs: BunchOfFields) {
                object : Al2.UpdateEntityParams() {
                    override fun shortOperationDescription() = "Edit order"
                    override fun entity() = juan.entity
                    override fun fields() = fs
                }.dance()
            }

            override fun makeFields() = when {
                rctx().isAdmin -> OrderFieldsForAdmin()
                else -> OrderFields()
            }

            override fun pagePath() = AlPagePath.order

            override fun addTabs(xs: MutableList<EntityPageTemplate.Tab>) {
                xs.add(FilesTab())
            }

            inner class FilesTab : EntityPageTemplate.Tab {
                override fun id() = filesTabID
                override fun title() = t("Files", "Файлы")

                override fun addTopRightControls(trb: TopRightControlsBuilder) {
                    trb.addOrderingSelect()
                    val canEdit: Boolean = canEditParams()
                    if (canEdit) {
                        trb.addButton(FA.plus, AlDebugTag.topRightButton, {buttonDomid ->
                            AlRender.bustOutModalOnDomidClick(juan.script, buttonDomid, ModalWithScripts.make {frc, frc2 ->
                                frc.fileValue = AlFileFormValue()
                                renderFileModalContent(frc2, null, FieldSource.Initial())
                            })
                        })
                    }
                }

                override fun render(rpp: RenderingParamsPile) = object : RenderPaginatedShit<AlUAOrderFile>() {
                    override fun makePageHref(pageFrom1: Int) =
                        juan.makeHrefKeepingEverythingExcept {it.page.set(pageFrom1)}

                    override fun renderItem(item: AlUAOrderFile) =
                        OrderPile2.renderOrderFileItem(juan.script, item, false)

                    override fun selectItems(offset: Long) =
                        AlDB.betty(AlDB_Params_betty_Builder.begin()
                                       .counting(false)
                                       .offset(offset)
                                       .orderID(juan.entity.id)
                                       .ordering(rctx().getParams.get().ordering.get()).end())
                            .selectCompound(AlUAOrderFile::class.java, null)

                    override fun count() =
                        AlDB.betty(AlDB_Params_betty_Builder.begin()
                                       .counting(true)
                                       .orderID(juan.entity.id).end())
                            .selectOneLong()

                    override fun initGivenItems(alUAOrderFileWithParams: List<AlUAOrderFile>) {}
                }.dance()

                fun renderFileModalContent(frc2: FormRenderingContext2, file: AlUAOrderFile?, source: FieldSource): Renderable {
                    val rmc = RenderModalContent()
                    rmc.title = when {
                        file == null -> t("TOTE", "Файл")
                        else -> t("TOTE", "Файл №" + file.id)
                    }
                    rmc.blueLeftMargin()
                    rmc.body = div().with {
                        val fields = Al.useFields(OrderFileFields(), source)
                        oo((fields.file as FileField).render(frc2)) // TODO:vgrechka Get rid of cast
                        oo(fields.title.render(frc2).focused())
                        oo(fields.details.render(frc2))
                    }
                    rmc.footer = ButtonBarWithTicker(rctx().script, frc2)
                        .tickerLocation(LeftOrRight.Left)
                        .addSubmitFormButton(MinimalButtonShit(
                            when {
                                file == null -> AlConst.Text.create
                                else -> AlConst.Text.save
                            },
                            AlButtonLevel2.Primary,
                            Servant {serveCreateOrUpdateFile(file)}),
                            rmc.errorBannerDomid)
                        .addCloseModalButton()
                    return rmc.dance()
                }

                private fun serveCreateOrUpdateFile(file: AlUAOrderFile?) {
                    val fs = Al.useFields(OrderFileFields(), FieldSource.Post())
                    val incomingFile = fs.file.value()

                    if (Al.anyFieldErrors(fs)) return run {
                        val frc2 = FormRenderingContext2()
                        frc2.shouldRestoreFilePickerValue = true // TODO:vgrechka Remove from context

                        AlCommands2.addEval {s -> s.replaceElement(
                            AlDomid.modalContent.name,
                            renderFileModalContent(frc2, file, FieldSource.Post()),
                            Supplier {frc2.initAndOnShowScripts()}
                        )}
                    }

                    if (Alk.isPreflight()) return run {
                        rctx().keepAdHocServantWithSameUUIDForNextRequest = true
                        AlCommands2.addEval(AlJS.invokeLastBackendCallTemplate(false, 0))
                    }

                    if (file == null) {
                        val cab = ContentAndBytesFromBase64(incomingFile.base64)
                        AlDB.insertEntity(cab.bytes)

                        AlDB.insertEntity(AlUAOrderFile_Builder.begin()
                            .uuid(Al.longUUID())
                            .orderID(juan.entity.id)
                            .state(AlUAOrderFileState.UNKNOWN)
                            .name(incomingFile.name)
                            .size(cab.content.size)
                            .title(fs.title.sanitized())
                            .details(fs.details.sanitized())
                            .bytesID(cab.bytes.getId())
                            .end())

                        // TODO:vgrechka Operations
                        // AlOperation operation = new AlOperationData_Rudimentary_V1(AlBasicOperationData_V1.make("Creating file")).toOperation();

                        AlCommands2.addCloseModal()
                        juan.reload()
                    }
                    else {
                        object : Al2.UpdateEntityParams() {
                            override fun entity() = file
                            override fun fields() = fs
                            override fun shortOperationDescription() = "Editing freaking file"
                        }.dance()

                        AlCommands2.addCloseModal()
                        imf("Replace shit")

//                        JSScriptBuilder script = new JSScriptBuilder();
//                        rctx().commands.add(also(new AlBackToFrontCommandPile(), o -> {
//                            o.opcode = AlBackToFrontCommandOpcode.ReplaceElement;
//                            o.domid = AlDomid.item;
//                            o.domidIndex = rctx().fileWithParams.get().entity.uuid;
//                            o.initCommands = new ArrayList<>();
//                            o.html = OrderPile2.renderOrderFileItem(script, rctx().fileWithParams.get(), true).render();
//                        }));
//                        rctx().addCommand(AlCommands2.eval(script.getCode()));
                    }
                }
            }

            override fun canEditParams() = when {
                juan.initialParams.impersonate.get() == AlUserKind.Admin -> true
                else -> juan.entity.state in setOf(
                    AlUAOrderState.CustomerDraft,
                    AlUAOrderState.ReturnedToCustomerForFixing)
            }

            override fun pageTitle() = t("TOTE", "Заказ №") + juan.entity.id

            override fun pageSubTitle() = juan.entity.documentTitle

            override fun renderActionBannerBelowTitle() = when {
                AlUAOrderState.CustomerDraft == juan.entity.state -> {
                    if (rctx().pretending.get() == AlUserKind.Customer)
                        ActionBanner()
                            .message(t("TOTE", "Убедись, что все верно. Подредактируй, если нужно. Возможно, добавь файлы. А затем..."))
                            .backgroundColor(Color.BLUE_GRAY_50)
                            .leftBorderColor(Color.BLUE_GRAY_300)
                            .accept {banner ->
                                banner.addButton(MinimalButtonShit(
                                    t("TOTE", "Отправить на проверку"), AlButtonLevel2.Primary,
                                    Servant {
                                        juan.changeEntityStateAndReload("Send order for approval", null, {p ->
                                            // 2a949363-293d-445f-a9f0-95ef1612b51e
                                            p.state = AlUAOrderState.WaitingAdminApproval;
                                        })
                                    }
                                ))
                            }
                    else div()
                }

                AlUAOrderState.ReturnedToCustomerForFixing == juan.entity.state -> object : RejectedBanner() {
                    override fun entityKindTitle() = "этот заказ"
                    override fun rejectionReason() = juan.entity.rejectionReason

                    override fun sendForReviewServant() = object : Servant {
                        override fun checkPermissions() = imf()
                        override fun ignite() = imf()
                    }
                }.dance()

                AlUAOrderState.WaitingAdminApproval == juan.entity.state -> object : RenderApprovalBanner() {
                    override fun performRejection(fs: RejectionFields) = imf()
                    override fun acceptButtonTitle() = t("TOTE", "В стор")
                    override fun entityKindTitle() = "заказ"
                    override fun rejectButtonTitle() = t("TOTE", "Завернуть")
                    override fun acceptServant() = imf()
                    override fun messageForUser() = t("TOTE", "Мы проверяем заказ и скоро с тобой свяжемся")
                    override fun questionForAdmin() = t("TOTE", "Что решаем по этому порожняку?")
                    override fun frc() = juan.frc
                    override fun frc2() = juan.frc2
                    override fun wasRejectionReason() = juan.entity.wasRejectionReason
                }.dance()

                else -> div()
            }

            override fun shitToGetParams(p: AlGetParams) =
                p.uuid.set(juan.entity.uuid)

            override fun renderBelowActionBanner() = when {
                rctx().pretending.get() == AlUserKind.Admin
                    && juan.entity.state == AlUAOrderState.WaitingAdminApproval
                    && !juan.entity.rejectionReason.isNullOrBlank()
                -> renderRejectionReason(AlConst.Text.potentialRejectionReason)
                else -> div()
            }

            override fun renderParamsTab(rpp: RenderingParamsPile): Renderable {
                val order = juan.entity
                var className: String? = null
                if (rpp.orderParamsClazz != null)
                    className = rpp.orderParamsClazz
                return div().domid(AlDomid.orderParams).style("position: relative;").className(className).with {
                    oo(Row().with {
                        oo(AlRender.createdAtCol(3, order.createdAt))
                        oo(AlRender.renderOrderStateColumn(order))
                    })

                    oo(Row().with {
                        oo(col(3, AlConst.Text.Order.contactName, order.contactName))
                        oo(col(3, AlConst.Text.Order.email, order.email))
                        oo(col(3, AlConst.Text.Order.phone, order.phone))
                    })

                    oo(Row().with {
                        oo(AlRender.orderDocumentTypeColumn(order))
                        oo(AlRender.orderDocumentCategoryColumn(order))
                    })

                    oo(AlRender.renderOrderNumsRow(order))

                    oo(DetailsRow().content(order.documentDetails))

                    if (rctx().pretending.get() == AlUserKind.Admin) {
                        if (!order.adminNotes.isNullOrBlank())
                            oo(DetailsRow().title(AlConst.Text.adminNotes).content(order.adminNotes))
                    }
                }
            }

            override fun shouldStopRenderingWithMessage() = when {
                rctx().pretending.get() == AlUserKind.Writer -> t("TOTE", "Никаким писателям этот заказ не виден")
                else -> null
            }


            fun renderRejectionReason(title: String) =
                AlRender.detailsWithUnderlinedTitle(title, juan.entity.rejectionReason)

            override fun shouldSkipField(fields: BunchOfFields, field: FormField<*>): Boolean {
                // TODO:vgrechka ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
                return false
            }

            override fun isPagePrivate() = AlGetParams().uuid.get() == null


            override fun getUUIDSupported() = true

            override fun checkPermissionsForEntityAccessedViaIDIfNotAdmin(entity: AlUAOrder) =
                when (rctx().userWP().kind) {
                    AlUserKind.Customer -> imf("Check that this customer is the one who created the order")
                    AlUserKind.Writer -> imf("Check that this writer is assigned to the order")
                    AlUserKind.Admin -> wtf()
                }
        }

        return t.build(pedro)
    }
}


