package main

import (
    "encoding/json"
    "flag"
    "net/http"
    "os"
    "strconv"
    "time"

    "github.com/sirupsen/logrus"
    "k8s.io/test-infra/pkg/flagutil"
    "k8s.io/test-infra/prow/config"
    "k8s.io/test-infra/prow/config/secret"
    prowflagutil "k8s.io/test-infra/prow/flagutil"
    configflagutil "k8s.io/test-infra/prow/flagutil/config"
    "k8s.io/test-infra/prow/github"
    "k8s.io/test-infra/prow/interrupts"
    "k8s.io/test-infra/prow/logrusutil"
    "k8s.io/test-infra/prow/pjutil"
    "k8s.io/test-infra/prow/pluginhelp"
    "k8s.io/test-infra/prow/pluginhelp/externalplugins"
)

const pluginName = "comment-plugin"

type options struct {
    port int

    config                 configflagutil.ConfigOptions
    dryRun                 bool
    github                 prowflagutil.GitHubOptions
    instrumentationOptions prowflagutil.InstrumentationOptions

    webhookSecretFile string
}

type server struct {
    tokenGenerator func() []byte
    botUser        *github.UserData
    email          string
    ghc            github.Client
    log            *logrus.Entry
    repos          []github.Repo
}

func helpProvider(_ []config.OrgRepo) (*pluginhelp.PluginHelp, error) {
    pluginHelp := &pluginhelp.PluginHelp{
       Description: `The sample plugin`,
    }
    return pluginHelp, nil
}

func (o *options) Validate() error {
    return nil
}

func gatherOptions() options {
    o := options{config: configflagutil.ConfigOptions{ConfigPath: "./config.yaml"}}
    fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
    fs.IntVar(&o.port, "port", 8888, "Port to listen on.")
    fs.BoolVar(&o.dryRun, "dry-run", false, "Dry run for testing. Uses API tokens but does not mutate.")
    fs.StringVar(&o.webhookSecretFile, "hmac-secret-file", "/etc/hmac", "Path to the file containing GitHub HMAC secret.")
    for _, group := range []flagutil.OptionGroup{&o.github} {
       group.AddFlags(fs)
    }
    fs.Parse(os.Args[1:])
    return o
}

func main() {
    o := gatherOptions()
    if err := o.Validate(); err != nil {
       logrus.Fatalf("Invalid options: %v", err)
    }

    logrusutil.ComponentInit()
    log := logrus.StandardLogger().WithField("plugin", pluginName)

    if err := secret.Add(o.webhookSecretFile); err != nil {
       logrus.WithError(err).Fatal("Error starting secrets agent.")
    }

    gitHubClient, err := o.github.GitHubClient(o.dryRun)
    if err != nil {
       logrus.WithError(err).Fatal("Error getting GitHub client.")
    }

    email, err := gitHubClient.Email()
    if err != nil {
       log.WithError(err).Fatal("Error getting bot e-mail.")
    }

    botUser, err := gitHubClient.BotUser()
    if err != nil {
       logrus.WithError(err).Fatal("Error getting bot name.")
    }
    repos, err := gitHubClient.GetRepos(botUser.Login, true)
    if err != nil {
       log.WithError(err).Fatal("Error listing bot repositories.")
    }
    serv := &server{
       tokenGenerator: secret.GetTokenGenerator(o.webhookSecretFile),
       botUser:        botUser,
       email:          email,
       ghc:            gitHubClient,
       log:            log,
       repos:          repos,
    }

    health := pjutil.NewHealthOnPort(o.instrumentationOptions.HealthPort)
    health.ServeReady()

    mux := http.NewServeMux()
    mux.Handle("/", serv)
    externalplugins.ServeExternalPluginHelp(mux, log, helpProvider)
    logrus.Info("starting server " + strconv.Itoa(o.port))
    httpServer := &http.Server{Addr: ":" + strconv.Itoa(o.port), Handler: mux}
    defer interrupts.WaitForGracefulShutdown()
    interrupts.ListenAndServe(httpServer, 5*time.Second)
}

func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    logrus.Info("inside http server")
    _, _, payload, ok, _ := github.ValidateWebhook(w, r, s.tokenGenerator)
    logrus.Info(string(payload))
    if !ok {
       return
    }
    logrus.Info(w, "Event received. Have a nice day.")
    if err := s.handleEvent(payload); err != nil {
       logrus.WithError(err).Error("Error parsing event.")
    }
}

func (s *server) handleEvent(payload []byte) error {
    logrus.Info("inside handler")
    var pr github.PullRequestEvent
    if err := json.Unmarshal(payload, &pr); err != nil {
       return err
    }
    logrus.Info(pr.Number)
    if err := s.ghc.CreateComment(pr.PullRequest.Base.Repo.Owner.Login, pr.PullRequest.Base.Repo.Name, pr.Number, "comment from smaple-plugin"); err != nil {
       return err
    }
    return nil
}