/*
 * Copyright (C) 2025-2025. Huawei Technologies Co., Ltd. All rights reserved.
 *
 * Licensed 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.
 */
use std::{
    hash::{Hash, Hasher},
    sync::atomic::{AtomicU32, Ordering},
};

use serde::Serialize;
use smallvec::SmallVec;

pub type NodeKey = u32;

pub const GRAPH_NODE: NodeKey = u32::MAX;
pub const EMPTY_NODEKEY: NodeKey = u32::MAX - 1;

pub static NODEKEY_COUNTER: AtomicU32 = AtomicU32::new(0);

pub fn unique_id() -> NodeKey {
    NODEKEY_COUNTER.fetch_add(1, Ordering::Relaxed)
}

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub struct EdgeKey {
    pub source: NodeKey,
    pub target: NodeKey,
}

impl Hash for EdgeKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let combined = ((self.source as u64) << 32) | (self.target as u64);
        combined.hash(state);
    }
}

pub fn keyof(source: NodeKey, target: NodeKey) -> EdgeKey {
    EdgeKey { source, target }
}

#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub enum Dummy {
    Root,
    Edge,
    EdgeProxy,
    Border,
    SelfEdge,
    #[default]
    None,
}

#[derive(Debug, Clone, Copy, Default)]
pub struct RankLimit {
    pub min: i32,
    pub max: i32,
}

#[derive(Debug, Clone, Copy, Default)]
pub struct GraphNode {
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    pub dummy: Dummy,
    pub rank: Option<i32>,
    pub rank_limit: Option<RankLimit>,
    pub order: Option<u32>,
    pub border_at_left: bool,
    pub active: bool,
}

impl GraphNode {
    pub fn of(width: f32, height: f32) -> GraphNode {
        GraphNode { width, height, active: true, ..GraphNode::default() }
    }
    
    pub fn new() -> GraphNode {
        GraphNode { active: true, ..GraphNode::default() }
    }
}

#[derive(Debug, Clone, Copy, Default, Serialize)]
pub struct Point {
    pub x: f32,
    pub y: f32,
}

impl Point {
    #[inline]
    pub fn new(x: f32, y: f32) -> Self {
        Self { x, y }
    }
}

#[derive(Debug, Clone)]
pub struct GraphEdge {
    pub min_len: f32,
    pub weight: f32,
    pub points: Option<SmallVec<Point, 4>>,
}

impl Default for GraphEdge {
    fn default() -> Self {
        Self { min_len: 1.0, weight: 1.0, points: None }
    }
}

impl GraphEdge {
    pub fn with_weight(weight: f32) -> Self {
        Self { min_len: 1.0, weight, points: None }
    }
}

#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub enum RankDir {
    LR,
    RL,
    #[default]
    TB,
    BT,
}

#[derive(Debug, Clone, Copy)]
pub struct GraphConfig {
    pub node_sep: f32,
    pub edge_sep: f32,
    pub rank_sep: f32,
    pub rank_dir: RankDir,
    pub nesting_root: Option<NodeKey>,
    pub node_rank_factor: Option<f32>,
}

impl Default for GraphConfig {
    fn default() -> Self {
        Self {
            node_sep: 50.0,
            edge_sep: 20.0,
            rank_sep: 50.0,
            rank_dir: RankDir::TB,
            nesting_root: None,
            node_rank_factor: None,
        }
    }
}