package service

import (
    "encoding/json"
    "fmt"
    "log"
    "os"
    "path/filepath"
    "strings"

	"safesight-control/internal/storage"
)

// ImportSeedAssets imports all config assets (templates, profiles, overlays) from a
// seed configs directory on first run. Returns total import count.
// The seed directory is expected to have subdirectories: templates/, profiles/, overlays/.
func ImportSeedAssets(repo *storage.AssetsRepo, seedDir string) (int, error) {
    if repo == nil {
        return 0, nil
    }
    seedDir = filepath.Clean(strings.TrimSpace(seedDir))
    if seedDir == "" {
        return 0, nil
    }
    if _, err := os.Stat(seedDir); os.IsNotExist(err) {
        return 0, nil
    }

    // Check if DB already has assets (not first run).
    existing, err := repo.ListTemplates()
    if err != nil {
        return 0, err
    }
    if len(existing) > 0 {
        return 0, nil
    }

    total := 0
    for _, kind := range []string{"templates", "profiles", "overlays"} {
        dir := filepath.Join(seedDir, kind)
        files, err := os.ReadDir(dir)
        if err != nil {
            if os.IsNotExist(err) {
                continue
            }
            return total, err
        }
        for _, f := range files {
            if f.IsDir() || !strings.HasSuffix(strings.ToLower(f.Name()), ".json") {
                continue
            }
            path := filepath.Join(dir, f.Name())
            body, err := os.ReadFile(path)
            if err != nil {
                return total, fmt.Errorf("%s: %w", path, err)
            }
            var raw map[string]any
            if err := json.Unmarshal(body, &raw); err != nil {
                return total, fmt.Errorf("%s: %w", path, err)
            }
            if raw == nil {
                raw = map[string]any{}
            }
            name := strings.TrimSpace(firstString(raw["name"], strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))))
            if name == "" {
                log.Printf("skip %s: empty name", path)
                continue
            }
            desc := stringValue(raw["description"])

            switch kind {
            case "templates":
                if strings.TrimSpace(stringValue(raw["source"])) == "" {
                    raw["source"] = "standard"
                }
                b, _ := marshalConfigJSON(raw)
                if err := repo.SaveTemplate(name, desc, string(b)); err != nil {
                    return total, fmt.Errorf("template %s: %w", name, err)
                }
            case "profiles":
                tmplName := stringValue(raw["primary_template_name"])
                bizName := stringValue(raw["business_name"])
                b, _ := marshalConfigJSON(raw)
                if err := repo.SaveProfile(name, tmplName, bizName, desc, string(b)); err != nil {
                    return total, fmt.Errorf("profile %s: %w", name, err)
                }
            case "overlays":
                b, _ := marshalConfigJSON(raw)
                if err := repo.SaveOverlay(name, desc, string(b)); err != nil {
                    return total, fmt.Errorf("overlay %s: %w", name, err)
                }
            }
            total++
        }
    }
    return total, nil
}

func ImportStandardTemplatesFromDir(repo *storage.AssetsRepo, dir string) (int, error) {
    if repo == nil {
        return 0, fmt.Errorf("asset repository is not configured")
    }
    dir = filepath.Clean(strings.TrimSpace(dir))
    if dir == "" {
        return 0, fmt.Errorf("standard template dir is empty")
    }
    files, err := os.ReadDir(dir)
    if err != nil {
        if os.IsNotExist(err) {
            return 0, nil
        }
        return 0, err
    }
    imported := 0
    for _, file := range files {
        if file.IsDir() || strings.ToLower(filepath.Ext(file.Name())) != ".json" {
            continue
        }
        path := filepath.Join(dir, file.Name())
        body, err := os.ReadFile(path)
        if err != nil {
            return imported, err
        }
        var raw map[string]any
        if err := json.Unmarshal(body, &raw); err != nil {
            return imported, fmt.Errorf("%s: %w", path, err)
        }
        if raw == nil {
            raw = map[string]any{}
        }
        name := strings.TrimSpace(firstString(raw["name"], strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))))
        if name == "" {
            return imported, fmt.Errorf("%s: template name is empty", path)
        }
        if err := validateConfigName(name); err != nil {
            return imported, fmt.Errorf("%s: invalid template name %q: %w", path, name, err)
        }
        if !isStandardTemplateName(name) {
            return imported, fmt.Errorf("%s: standard template name must start with std_", path)
        }
        if strings.TrimSpace(stringValue(raw["source"])) == "" {
            raw["source"] = "standard"
        }
        body, err = marshalConfigJSON(raw)
        if err != nil {
            return imported, err
        }
        existing, err := repo.GetTemplate(name)
        if err != nil {
            return imported, err
        }
        if existing != nil &&
            strings.TrimSpace(existing.Description) == strings.TrimSpace(stringValue(raw["description"])) &&
            strings.TrimSpace(existing.BodyJSON) == strings.TrimSpace(string(body)) {
            continue
        }
        if err := repo.SaveTemplate(name, stringValue(raw["description"]), string(body)); err != nil {
            return imported, err
        }
        imported++
    }
    return imported, nil
}

func ImportStandardOverlaysFromDir(repo *storage.AssetsRepo, dir string) (int, error) {
    if repo == nil {
        return 0, fmt.Errorf("asset repository is not configured")
    }
    dir = filepath.Clean(strings.TrimSpace(dir))
    if dir == "" {
        return 0, fmt.Errorf("standard overlay dir is empty")
    }
    files, err := os.ReadDir(dir)
    if err != nil {
        if os.IsNotExist(err) {
            return 0, nil
        }
        return 0, err
    }
    imported := 0
    for _, file := range files {
        if file.IsDir() || strings.ToLower(filepath.Ext(file.Name())) != ".json" {
            continue
        }
        path := filepath.Join(dir, file.Name())
        body, err := os.ReadFile(path)
        if err != nil {
            return imported, err
        }
        var raw map[string]any
        if err := json.Unmarshal(body, &raw); err != nil {
            return imported, fmt.Errorf("%s: %w", path, err)
        }
        if raw == nil {
            raw = map[string]any{}
        }
        name := strings.TrimSpace(firstString(raw["name"], strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))))
        if name == "" {
            return imported, fmt.Errorf("%s: overlay name is empty", path)
        }
        if err := validateConfigName(name); err != nil {
            return imported, fmt.Errorf("%s: invalid overlay name %q: %w", path, name, err)
        }
        if !isStandardTemplateName(name) {
            return imported, fmt.Errorf("%s: standard overlay name must start with std_", path)
        }
        description := strings.TrimSpace(stringValue(raw["description"]))
        delete(raw, "name")
        delete(raw, "description")
        body, err = marshalConfigJSON(raw)
        if err != nil {
            return imported, err
        }
        existing, err := repo.GetOverlay(name)
        if err != nil {
            return imported, err
        }
        if existing != nil &&
            strings.TrimSpace(existing.Description) == description &&
            strings.TrimSpace(existing.BodyJSON) == strings.TrimSpace(string(body)) {
            continue
        }
        if err := repo.SaveOverlay(name, description, string(body)); err != nil {
            return imported, err
        }
        imported++
    }
    return imported, nil
}

// EnsureDefaultIntegrations creates the default alarm and storage integration
// services if they don't already exist. Call during startup.
func EnsureDefaultIntegrations(repo *storage.AssetsRepo) error {
    defaults := []struct {
        Name        string
        ServiceType string
        Description string
        Enabled     bool
        BodyJSON    string
    }{
        {
            Name:        "alarm",
            ServiceType: "alarm_service",
            Description: "告警推送 HTTP API",
            Enabled:     true,
            BodyJSON:    `{"get_token_url":"http://10.0.0.49:8080/api/getToken","put_message_url":"http://10.0.0.49:8080/api/putMessage","tenant_code":"32"}`,
        },
        {
            Name:        "storage",
            ServiceType: "object_storage",
            Description: "告警截图和视频存储",
            Enabled:     true,
            BodyJSON:    `{"endpoint":"http://10.0.0.49:9000","bucket":"myminio","access_key":"admin","secret_key":"password"}`,
        },
    }
    for _, item := range defaults {
        existing, _ := repo.GetIntegrationService(item.Name)
        if existing != nil {
            continue
        }
        if err := repo.SaveIntegrationService(item.Name, item.ServiceType, item.Description, item.Enabled, item.BodyJSON); err != nil {
            return err
        }
    }
    return nil
}
