use super::state::ApiState;
use axum::extract::{Query, State};
use axum::response::Html as html;
use build_html::{Html, HtmlContainer, Table, TableCell, TableCellType, TableRow};
use log::*;
use model::report::PipelineReport;
use serde::Deserialize;
use sqlx::types::chrono::FixedOffset;

#[derive(Debug, Deserialize)]
pub(crate) struct Pagination {
    page: Option<u64>,
    per_page: Option<u64>,
    user: Option<String>,
}

const ALLOW_USERS: [&str; 2] = ["xiezhi", "sunxiaoguang"];

impl Default for Pagination {
    fn default() -> Self {
        Pagination {
            page: Some(1),
            per_page: Some(10),
            user: None,
        }
    }
}

impl Pagination {
    fn offset(&self) -> u64 {
        (self.page.unwrap_or(1) - 1) * self.per_page.unwrap_or(10)
    }

    fn limit(&self) -> u64 {
        self.per_page.unwrap_or(10)
    }
}

#[derive(Deserialize)]
pub struct SourceReport {
    pub successes: i64,
    // pub tenant_faileds: Vec<String>,
    pub cost: std::time::Duration,
}

#[derive(Deserialize)]
pub struct SinkReport {
    pub successes: i64,
    pub deletes: i64,
    // pub cost: std::time::Duration,
}

pub async fn list_pipeline_reports(
    State(state): State<ApiState>,
    Query(paging): Query<Pagination>,
) -> html<String> {
    if paging.user.is_none() || !ALLOW_USERS.contains(&paging.user.as_deref().unwrap()) {
        return html("Not allowed".to_string());
    }

    info!("List pipeline reports: {:?}", paging);

    let db = match state.get_meta_db().await {
        Some(db) => db,
        None => return html("Meta DB not configured".to_string()),
    };

    let reports = PipelineReport::find_offset(&db, paging.offset(), paging.limit())
        .await
        .unwrap();
    let mut table = Table::new().with_attributes([
        ("border", "1"),
        ("cellpadding", "5"),
        ("width", "100%"),
        ("cellspacing", "0"),
    ]);
    table.add_custom_header_row(
        TableRow::new()
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("colspan", "2")])
                    .with_raw("Collections"),
            )
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("colspan", "2")])
                    .with_raw("Documents"),
            )
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("colspan", "2")])
                    .with_raw("Index"),
            )
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("rowspan", "2")])
                    .with_raw("Total cost(ms)"),
            )
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("colspan", "3")])
                    .with_raw("Versions"),
            )
            .with_cell(
                TableCell::new(TableCellType::Header)
                    .with_attributes([("rowspan", "2")])
                    .with_raw("Created at"),
            ),
    );
    table.add_custom_header_row(
        TableRow::new()
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Successes"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Cost(ms)"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Successes"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Cost(ms)"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Successes"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Deleteds"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Meta"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("Start"))
            .with_cell(TableCell::new(TableCellType::Header).with_raw("End")),
    );

    for report in reports {
        let collection_source: SourceReport =
            serde_json::from_str(&report.collection_source).unwrap();
        let documents_source: SourceReport =
            serde_json::from_str(&report.documents_source).unwrap();
        let sink_report: SinkReport = serde_json::from_str(&report.index_sink).unwrap();
        table.add_custom_body_row(
            TableRow::new()
                .with_cell(
                    TableCell::new(TableCellType::Data)
                        .with_raw(collection_source.successes.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data)
                        .with_raw(collection_source.cost.as_millis()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data)
                        .with_raw(documents_source.successes.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(documents_source.cost.as_millis()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(sink_report.successes.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(sink_report.deletes.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(report.cost_millis.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(report.meta_version.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(report.start_version.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(report.end_version.to_string()),
                )
                .with_cell(
                    TableCell::new(TableCellType::Data).with_raw(
                        report
                            .created_at
                            .checked_add_offset(FixedOffset::east_opt(3600 * 8).unwrap())
                            .unwrap()
                            .to_string(),
                    ),
                ),
        );
    }

    html(table.to_html_string())
}
