// Package db defines the database schema.
package database

import (
	"database/sql"
	"fmt"
)

func BaseTables() []string {

	datalist := []string{}

	Appliances := `
    CREATE TABLE IF NOT EXISTS appliances (
        ID              integer primary key autoincrement,
        Name            varchar(32) not null default '',
        Graph           varchar(64) not null default 'default',
        Node            varchar(64) not null default '',
        OS              varchar(64) not null default 'linux'
    );
    `
	datalist = append(datalist, Appliances)

	Memberships := `
    CREATE TABLE IF NOT EXISTS memberships (
        ID              integer primary key autoincrement,
        Name            varchar(64) not null default '',
        Appliance       integer(11) default '0',
        Distribution    integer(11) default '1',
        Public          varchar(64) not null default 'no'
    );
    `
	datalist = append(datalist, Memberships)

	Categories := `
    CREATE TABLE IF NOT EXISTS categories (
        ID              integer primary key autoincrement,
        Name            varchar(64) not null unique default '0',
        Description     varchar(255) default null,
        UNIQUE(Name)
    );
    `
	datalist = append(datalist, Categories)

	Catindex := `
    CREATE TABLE IF NOT EXISTS catindex (
        ID              integer primary key autoincrement,
        Name            varchar(64) not null unique default '0',
        Category        integer not null,
        Foreign key(Category) references categories(ID) on delete cascade
    );
    `
	datalist = append(datalist, Catindex)

	Resolvechain := `
    CREATE TABLE IF NOT EXISTS resolvechain (
        ID              integer primary key autoincrement,
        Name            varchar(64) not null default '0',
        Category        integer(11) not null,
        Precedence      integer(11) not null default '10',
        UNIQUE(Name, Category)
        Foreign key(Category) references categories(ID) on delete cascade
    );
    `
	datalist = append(datalist, Resolvechain)

	Nodes := `
    CREATE TABLE IF NOT EXISTS nodes (
        ID              integer primary key autoincrement,
        Name            varchar(128) default null,
        Membership      integer(11) default '2',
        CPUs            integer(11) not null default '1',
        Rack            varchar(11) default null,
        Rank            integer(11) default null,
        Arch            varchar(32) default null,
        OS              varchar(64) not null default 'linux',
        RunAction       varchar(64) default 'os',
        InstallAction   varchar(64) default 'install'
    );
    create index if not exists idx_nodes_name on nodes(Name);
    `
	datalist = append(datalist, Nodes)

	Aliases := `
    CREATE TABLE IF NOT EXISTS aliases (
        ID              integer primary key autoincrement,
        Node            integer(15) not null default '0',
        Name            varchar(32) default null,
        Foreign key(Node) references nodes(ID) on delete cascade
    );
    `
	datalist = append(datalist, Aliases)

	Networks := `
    CREATE TABLE IF NOT EXISTS networks (
        ID          integer primary key autoincrement,
        Node        integer(11) default null,
        MAC         varchar(64) default null,
        IP          varchar(64) default null,
        Name        varchar(128) default null,
        Device      varchar(32) default null,
        Subnet      integer(11) default null,
        Module      varchar(128) default null,
        VlanID      integer(11) default null,
        Options     varchar(128) default null,
        Channel     varchar(128) default null,
        Foreign key(Node) references nodes(ID) on delete cascade,
        Foreign key(Subnet) references subnets(ID) on delete cascade
    );
    `
	datalist = append(datalist, Networks)

	GlobalRoutes := `
    CREATE TABLE IF NOT EXISTS globalroutes (
        Network     varchar(32) not null default '',
        Netmask     varchar(32) not null default '',
        Gateway     varchar(32) not null default '',
        Subnet      integer(11) default null,
        Primary key(Network, Netmask)
        Foreign key(Subnet) references subnets(ID) on delete cascade
    );
    `
	datalist = append(datalist, GlobalRoutes)

	OSRoutes := `
    CREATE TABLE IF NOT EXISTS osroutes (
        OS          varchar(64) not null default 'linux',
        Network     varchar(32) not null default '',
        Netmask     varchar(32) not null default '',
        Gateway     varchar(32) not null default '',
        Subnet      integer(11) default null,
        Primary key(OS, Network, Netmask)
        Foreign key(Subnet) references subnets(ID) on delete cascade
    );
    `
	datalist = append(datalist, OSRoutes)

	ApplianceRoutes := `
    CREATE TABLE IF NOT EXISTS applianceroutes (
        Appliance   varchar(11) not null default '0',
        Network     varchar(32) not null default '',
        Netmask     varchar(32) not null default '',
        Gateway     varchar(32) not null default '',
        Subnet      integer(11) default null,
        Primary key(Appliance, Network, Netmask)
        Foreign key(Subnet) references subnets(ID) on delete cascade
    );
    `
	datalist = append(datalist, ApplianceRoutes)

	NodeRoutes := `
    CREATE TABLE IF NOT EXISTS noderoutes (
        Node        varchar(11) not null default '0',
        Network     varchar(32) not null default '',
        Netmask     varchar(32) not null default '',
        Gateway     varchar(32) not null default '',
        Subnet      integer(11) default null,
        Primary key(Node, Network, Netmask)
        Foreign key(Subnet) references subnets(ID) on delete cascade
    );
    `
	datalist = append(datalist, NodeRoutes)

	Subnets := `
    CREATE TABLE IF NOT EXISTS subnets (
        ID          integer primary key autoincrement,
        name        varchar(32) unique not null,
        dnszone     varchar(64) unique not null,
        subnet      varchar(32) default null,
        netmask     varchar(32) default null,
        mtu         integer(11) default '1500',
        servedns    boolean default false
    );
    `
	datalist = append(datalist, Subnets)

	PublicKeys := `
    CREATE TABLE IF NOT EXISTS publickeys (
        ID          integer primary key autoincrement,
        Node        integer(11) not null default '0',
        Public_Key  varchar(8192) default null,
        Description varchar(8192) default null,
        Foreign key(Node) references nodes(ID) on delete cascade
    );
    `
	datalist = append(datalist, PublicKeys)

	SecGlobal := `
    CREATE TABLE IF NOT EXISTS secglobal (
        Attr        varchar(128) default null,
        Value       text,
        Enc         varchar(128) default null,
        Primary key(Attr)
    );
    `
	datalist = append(datalist, SecGlobal)

	SecNodes := `
    CREATE TABLE IF NOT EXISTS secnodes (
        Attr        varchar(128) default null,
        Enc         varchar(128) default null,
        Value       text,
        Node        integer(15) not null default '0',
        Primary key(Attr, Node)
    );
    `
	datalist = append(datalist, SecNodes)

	Attributes := `
    CREATE TABLE IF NOT EXISTS attributes (
        ID          integer primary key autoincrement,
        Attr        varchar(128) not null,
        Value       text,
        Shadow      text,
        Category    integer(11) not null,
        Catindex    integer(11) not null,
        UNIQUE(Attr, Category, Catindex),
        Foreign key(Catindex) references catindex(ID) on delete cascade
    );
    `
	datalist = append(datalist, Attributes)

	Partitions := `
    CREATE TABLE IF NOT EXISTS partitions (
        ID              integer primary key autoincrement,
        Node            integer(15) not null default '0',
        Device          varchar(128) not null default '',
        MountPoint      varchar(128) not null default '',
        SectorStart     varchar(128) not null default '',
        PartitionSize   varchar(128) not null default '',
        FsType          varchar(128) not null default '',
        PartitionFlags  varchar(128) not null default '',
        FormatFlags     varchar(128) not null default ''
    );
    `
	datalist = append(datalist, Partitions)

	Firewalls := `
    CREATE TABLE IF NOT EXISTS firewalls (
        ID              integer primary key autoincrement,
        Rulename        varchar(128) not null,
        Rulesrc         varchar(256) not null default 'custom',
        InSubnet        int(11),
        OutSubnet       int(11),
        Service         varchar(256),
        Protocol        varchar(256),
        Action          varchar(256),
        Chain           varchar(256),
        Flags           varchar(256),
        Comment         varchar(256),
        Category        integer(11) not null,
        Catindex        integer(11) not null,
        Check(rulesrc IN ('system', 'custom'))
        UNIQUE(Rulename, Category, Catindex),
        Foreign key(Catindex) references catindex(ID) on delete cascade
    );
    `
	datalist = append(datalist, Firewalls)

	Rolls := `
    CREATE TABLE IF NOT EXISTS rolls (
        ID              integer primary key autoincrement,
        Name            varchar(128) not null default '',
        Version         varchar(32) not null default '',
        Arch            varchar(32) not null default '',
        OS              varchar(64) not null default 'linux',
        Enabled         varchar(3) not null default 'yes',
        Check(Enabled IN ('yes', 'no'))
        Check(OS IN ('linux', 'other'))
    );
    `
	datalist = append(datalist, Rolls)

	NodeRolls := `
    CREATE TABLE IF NOT EXISTS noderolls (
        Node        varchar(11) not null default '0',
        RollID      varchar(11) not null,
        Primary key(Node, RollID)
    );
    `
	datalist = append(datalist, NodeRolls)

	Bootactions := `
    CREATE TABLE IF NOT EXISTS bootactions (
        ID              integer primary key autoincrement,
        Action          varchar(256) default null,
        Kernel          varchar(256) default null,
        Ramdisk         varchar(256) default null,
        Args            varchar(1024) default null
    );
    `
	datalist = append(datalist, Bootactions)

	BootFlags := `
    CREATE TABLE IF NOT EXISTS bootflags (
        ID              integer primary key autoincrement,
        Node            integer(11) not null default '0',
        Flags           varchar(256) default null
    );
    `
	datalist = append(datalist, BootFlags)

	Distributions := `
    CREATE TABLE IF NOT EXISTS distributions (
        ID              integer primary key autoincrement,
        Name            varchar(32) not null default '',
        OS              varchar(32) default '',
        Release         varchar(32) default ''
    );
    `
	datalist = append(datalist, Distributions)

	View_vnet := `
    DROP VIEW IF EXISTS vnet;
    CREATE VIEW vnet AS
        SELECT
            n.name AS nodename,     /* 查询nodes表中name字段,将字段改名为nodename */
            m.name AS membership,
            a.name AS appliance,
            n.rack, n.rank,         /* 查询nodes表中rack和rank字段,使用原始字段名 */
            s.name AS subnet, 
            nt.ip, nt.device, nt.module,
            nt.name AS hostname,
            s.dnszone AS domainname,
            s.netmask, s.mtu
        FROM 
            nodes n /* 主表: 先查询nodes表,别名n */
        inner join memberships m on n.membership=m.id /* 连接memberships表,on只保留满足条件的行 */
        inner join appliances a on m.appliance=a.id /* 连接appliances表,on只保留满足条件的行 */
        inner join networks nt on n.id=nt.node /* 连接networks表,on只保留满足条件的行 */
        inner join subnets s on nt.subnet=s.id /* 连接subnets表,on只保留满足条件的行 */
    ;
    `
	datalist = append(datalist, View_vnet)

	View_hostselections := `
    DROP VIEW IF EXISTS hostselections;
    CREATE VIEW hostselections AS
        SELECT
            n.name AS host,
            c.id as category,
            ci.id as selection
        FROM 
            nodes n
        inner join memberships m on n.membership=m.id   -- 节点表关联所属分组
        inner join appliances a on m.appliance=a.id     -- 分组关联所属应用角色
        inner join categories c on 
            -- 匹配4类分层配置的category(全局/OS/应用/主机)
            c.name in ('global', 'os', 'appliance', 'host')
        inner join catindex ci on 
            -- 核心匹配逻辑: category和catindex的name字段一一对应
            (c.name = 'global' and ci.name = 'global') or
            (c.name = 'os' and ci.name = n.os) or
            (c.name = 'appliance' and ci.name = a.name) or
            (c.name = 'host' and ci.name = n.name)
    ;
    `
	datalist = append(datalist, View_hostselections)

	View_vcatindex := `
    -- 视图vcatindex: 类别索引可读试图
    DROP VIEW IF EXISTS vcatindex;
    CREATE VIEW vcatindex AS
        SELECT
            c.id AS ID,
            cat.Name AS Category,
            ci.Name AS catindex
        FROM 
            categories cat
        inner join catindex ci on ci.category=cat.id
    ;
    `
	datalist = append(datalist, View_vcatindex)

	View_vresolvechain := `
    -- 视图vresolvechain: 解析链可读试图
    DROP VIEW IF EXISTS vresolvechain;
    CREATE VIEW vresolvechain AS
        SELECT
            r.name AS chain,
            cat.name AS category,
            precedence
        FROM 
            resolvechain r
        inner join categories cat on r.category=cat.id
        order by chain, precedence
    ;
    `
	datalist = append(datalist, View_vresolvechain)

	View_vattributes := `
    -- 视图vattributes: 属性可读试图
    DROP VIEW IF EXISTS vattributes;
    CREATE VIEW vattributes AS
        SELECT
            a.id,
            attr,
            value,
            shadow,
            cat.name AS category,
            ci.name AS catindex
        FROM 
            attributes a
        inner join catindex ci on a.catindex=ci.id
        inner join categories cat on a.category=cat.id
        order by attr, catindex, category
    ;
    `
	datalist = append(datalist, View_vattributes)

	View_vfirewalls := `
    -- 视图vfirewalls: 防火墙规则可读试图
    DROP VIEW IF EXISTS vfirewalls;
    CREATE VIEW vfirewalls AS
        SELECT
            f.id,
            f.Rulename,
            f.Rulesrc,
            f.InSubnet,
            f.OutSubnet,
            f.Service,
            f.Protocol,
            f.Action,
            f.Chain,
            f.Flags,
            f.Comment,
            cat.name AS category,
            ci.name AS catindex
        FROM 
            firewalls f
        inner join catindex ci on f.catindex=ci.id
        inner join categories cat on f.category=cat.id
        order by f.Rulename, catindex, category
    ;
    `
	datalist = append(datalist, View_vfirewalls)

	View_vhostselections := `
    -- 视图vhostselections: 主机选择可读试图
    DROP VIEW IF EXISTS vhostselections;
    CREATE VIEW vhostselections AS
        SELECT
            hs.host AS host,
            cat.name AS category,
            ci.name AS selection
        FROM 
            hostselections hs
        inner join categories cat on hs.category=cat.id
        inner join catindex ci on hs.selection=ci.id
        order by host, category, selection
    ;
    `
	datalist = append(datalist, View_vhostselections)

	View_vmapCategoryIndex := `
    -- 视图vmapcategoryindex: 类别索引映射可读试图
    DROP VIEW IF EXISTS vmapcategoryindex;
    CREATE VIEW vmapCategoryIndex AS
        SELECT
            cat.name AS categoryName,
            ci.name AS categoryIndex,
            ci.ID AS index_ID
        FROM 
            cateindex ci
        inner join categories cat on ci.category=cat.id
    ;
    `
	datalist = append(datalist, View_vmapCategoryIndex)

	return datalist
}

func InitBaseData(conn *sql.DB) error {
	// ========== 第一步：插入 categories 数据 ==========
	categoryData := []struct {
		Name        string
		Description string
	}{
		{"global", "Global Defaults"},
		{"os", "OS Choice(Linux,Sunos)"},
		{"appliance", "Logical Appliances"},
		{"rack", "Machine Room Racks"},
		{"host", "Hosts - Physical AND Virtual"},
	}

	// 批量插入 categories (忽略重复)
	for _, cd := range categoryData {
		query := `
            insert or ignore into categories (Name, Description)
            values (?, ?)
        `
		_, err := conn.Exec(query, cd.Name, cd.Description)
		if err != nil {
			return fmt.Errorf("error inserting category %s: %w", cd.Name, err)
		}
	}

	// ========== 第二步：插入 catindex 数据 ==========
	catindexData := []struct {
		Name     string
		Category string
	}{
		{"global", "global"},
		{"linux", "os"},
		{"sunos", "os"},
		{"frontend", "appliance"},
		{"compute", "appliance"},
		{"nas", "appliance"},
		{"network", "appliance"},
		{"power", "appliance"},
		{"devel-server", "appliance"},
		{"login", "appliance"},
	}
	// 批量插入 catindex (忽略重复)
	for _, ci := range catindexData {
		// 动态获取类别ID (复用MapCategory函数)
		catID, err := MapCategory(conn, ci.Category)
		if err != nil {
			return fmt.Errorf("error mapping category %s: %w", ci.Category, err)
		}
		if catID == 0 {
			return fmt.Errorf("category %s not found", ci.Category)
		}

		// 插入 catindex (忽略重复)
		query := `
            insert or ignore into catindex (Name, Category)
            values (?, ?)
        `
		_, err = conn.Exec(query, ci.Name, catID)
		if err != nil {
			return fmt.Errorf("error inserting catindex %s: %w", ci.Name, err)
		}
	}

	// ========== 第三步：插入 resolvechain 数据 ==========
	resolveChainData := []struct {
		Name       string // 解析链名称,global/linux/sunos
		Category   string // 类别名称,linux/sunos
		Precedence int    // 优先级,数值越大优先级越高
	}{
		{"default", "global", 10},
		{"default", "os", 20},
		{"default", "appliance", 30},
		{"default", "rack", 40},
		{"default", "host", 50},
	}
	// 批量插入 resolvechain (忽略重复)
	for _, rcd := range resolveChainData {
		// 动态获取类别ID (复用MapCategory函数)
		catID, err := MapCategory(conn, rcd.Category)
		if err != nil {
			return fmt.Errorf("error mapping category %s: %w", rcd.Category, err)
		}
		if catID == 0 {
			return fmt.Errorf("category %s not found", rcd.Category)
		}

		// 插入 resolvechain (忽略重复)
		query := `
            insert or ignore into resolvechain (Name, Category, Precedence)
            values (?, ?, ?)
        `
		_, err = conn.Exec(query, rcd.Name, catID, rcd.Precedence)
		if err != nil {
			return fmt.Errorf("error inserting resolvechain %s: %w", rcd.Name, err)
		}
	}

	return nil
}
