import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { AccessControl } from 'accesscontrol';
import { FormUtils } from 'src/app/lib/utils/form-utils';
import { AuthService } from 'src/app/auth/auth.service';
import { SysService } from './sys.service';
import { ActionType, PossessionType } from 'src/app/auth/interfaces';
import { forkJoin } from 'rxjs';


@Component({
  selector: 'sys-role-edit',
  template: `

  <nz-spin nzDelay="500" [nzSpinning]="isLoading">
    <form *ngIf="form" nz-form [formGroup]="form" (ngSubmit)="submit()" >

      <nz-form-item>
        <nz-form-control i18n-nzErrorTip nzErrorTip="角色名不能为空">
          <nz-input-group nzPrefixIcon="user">
            <input nz-input formControlName="name" i18n-placeholder placeholder="角色名称">
          </nz-input-group>
        </nz-form-control>
      </nz-form-item>

      <div class="m-3">
        <table class="table table-borderless">
          <tbody>
            <ng-container *ngFor="let resource of resources;"  >
              <tr *ngIf="myGrantsFormValue && myGrantsFormValue[resource.value]" >
                <th>{{resource.label}}</th>
                <td *ngFor="let action of actions" [formGroup]="getActionForm(resource.value, action.value)" >
                  <div class="d-flex flex-row align-items-center">
                    <nz-form-item>
                      <label nz-checkbox formControlName="active" (ngModelChange)="toggle(resource.value, action.value)" >{{action.label}}</label> 
                    </nz-form-item>
                    <nz-form-item>
                      <nz-form-control>
                        <nz-select  i18n-nzPlaceHolder nzPlaceHolder="所属" formControlName="possession" [nzOptions]="getPossession(resource.value, action.value) == 'any' ? possessions : possessions_own "  > </nz-select>
                      </nz-form-control>
                    </nz-form-item>
                  </div>
                </td>
              </tr>
            </ng-container>
          </tbody>
        </table>
      </div>

      <div class="d-flex flex-row  justify-content-center gap-2 m-4">
        <button nz-button type="button" (click)="reset()" i18n>重置 </button>
        <button nz-button type="submit" [disabled]="!isDirty" nzType="primary" i18n>保存</button>
      </div>
    </form>
  </nz-spin>



  <ng-container *ngIf="debug">
    
    <p>grantsForm.valid: {{grantsForm.valid}} </p>
    <p>form.valid: {{form.valid}} </p>

    <div class="row">
      <div class="col">
        <p>myGrants:</p>
        <pre>{{myGrants | json}} </pre>
      </div>
      <div class="col">
        <p>myGrantsFormValue:</p>
        <pre>{{myGrantsFormValue | json}} </pre>
      </div>
      <div class="col">
        <p>resourceForm:</p>
        <pre>{{grantsForm.value | json}} </pre>
      </div>
      <div class="col">
        <p>output:</p>
        <pre>{{formToGrants| json  }}</pre>
      </div>
      <div class="col">
        <p>input:</p>
        <pre>{{input | json  }}</pre>
      </div>
      <div class="col">
        <p>grants:</p>
        <pre>{{grants | json  }}</pre>
      </div>
    </div>
  </ng-container>


  `,
  styles: [
    `
    .ant-form-item{
      margin-bottom:0;
    }
    `
  ]
})
export class RoleEditComponent implements OnInit {

  @Output() onSuccess = new EventEmitter<any>();
  @Output() onError = new EventEmitter<any>();

  @Input() debug: boolean = false;

  isLoading: boolean = false;
  private role: any;


  @Input() roleId: string;


  resources = [
    { value: 'art', label: $localize`作品` },
    { value: 'art-comment', label: $localize`作品评价` },
    { value: 'user', label: $localize`用户` },
    { value: 'role', label: $localize`角色` },
  ];

  actions = [
    { value: 'read', label: $localize`查看` },
    { value: 'create', label: $localize`创建` },
    { value: 'update', label: $localize`更新` },
    { value: 'delete', label: $localize`删除` },
  ];

  possessions = [
    { value: 'own', label: $localize`自己的` },
    { value: 'any', label: $localize`全部` },
  ];

  possessions_own = [
    { value: 'own', label: $localize`自己的` },
  ];

  form: FormGroup;
  formUtils = FormUtils;
  defaultValues: any;
  grantsForm: FormGroup;


  myGrants: any;
  myGrantsFormValue: any;


  constructor(
    private fb: FormBuilder,
    private sys: SysService,
    private message: NzMessageService,
  ) {


  }

  ngOnInit(): void {
    console.log('roleId', this.roleId);

    let request = [this.sys.getGrants(), this.sys.getAuthConfig()];
    if (this.roleId) request.push(this.sys.getRole(this.roleId))


    this.isLoading = true;
    forkJoin(request).subscribe({
      next: (resp: [any, any, any]) => {
        this.isLoading = false;

        let [myGrants, authConfig, role] = resp;
        this.myGrants = myGrants;
        this.myGrantsFormValue = this.grantsToFormInput(myGrants);

        let { resources, actions, possessions } = authConfig;
        this.resources = resources;
        this.actions = actions;
        this.possessions = possessions;

        this.grantsForm = this.fb.group(
          this.resources.reduce((last, res) => {
            last[res.value] = this.fb.group(
              this.actions.reduce((l, action) => {
                l[action.value] = this.fb.group({ active: false, possession: ['own', [Validators.required]], attributes: ['*'] });
                return l;
              }, {})
            )
            return last;
          }, {})
        );

        this.form = this.fb.group({
          name: [null, [Validators.required]],
          grants: this.grantsForm,
        });

        this.defaultValues = this.grantsForm.value;

        if (role) {
          this.role = role;
          this.setValue(this.role);
        }

      },
      error: err => {
        this.message.error(err.error?.message || err.message);
      }
    })
  }

  /**
   * 设置表单初始值
   * @param role 
   */
  private setValue(role: any) {
    this.form.controls['name'].setValue(role.name);
    let grantsValue = this.grantsToFormInput(role.grants);
    let grantsFormValue = {};
    this.resources.forEach(res => {
      this.actions.forEach(act => {
        grantsFormValue[res.value] = grantsFormValue[res.value] || {};
        grantsFormValue[res.value][act.value] = this.getValue(grantsValue, res.value, act.value) || { active: false, possession: 'own', attributes: '*' };
      })
    })
    this.grantsForm.reset(grantsFormValue);
    this.toggleAll();
  }

  private getValue(value: any, resource: string, action: string) {
    if (!value || !value[resource] || !value[resource][action]) return null;
    return value[resource][action];
  }



  getActionForm(resource: string, action: string): FormGroup {
    let resourceForm = this.grantsForm.controls[resource] as FormGroup;
    let actionsForm = resourceForm.controls[action] as FormGroup;
    return actionsForm;
  }

  getPossession(resource: string, action: string): PossessionType | null {
    if (!this.myGrantsFormValue) return null;
    if (!this.myGrantsFormValue[resource]) return null;
    if (!this.myGrantsFormValue[resource][action]) return null;
    return this.myGrantsFormValue[resource][action]['possession'];
  }

  getPossessionOptions(resource: string, action: string) {
    let p = this.getPossession(resource, action);
    if (p == 'any') return this.possessions;
    else if (p == 'own') return this.possessions_own;
    else return [];
  }

  toggleAll() {
    this.resources.forEach(res => {
      this.actions.forEach(act => {
        this.toggle(res.value, act.value);
        //disable action form is I don't have any grants.
        let actionForm = this.getActionForm(res.value, act.value);
        let possession = this.getPossession(res.value, act.value);
        //console.log('possession', possession);
        if (!possession) actionForm.disable();
      })
    })
  }

  toggle(resource: string, action: string): void {
    let actionForm = this.getActionForm(resource, action);
    actionForm.value.active ?
      actionForm.controls['possession'].enable() :
      actionForm.controls['possession'].disable();
  }

  /**
   * 将GrantForm转化为grant存储类型
   */
  get formToGrants(): GrantStorageItem[] {
    let auth = [];
    this.resources.forEach(res => {
      this.actions.forEach(act => {
        let f = this.getActionForm(res.value, act.value);
        let { active, possession, attributes } = f.value as ActionItem;
        if (active) {
          let item: GrantStorageItem = {
            resource: res.value,
            action: act.value as ActionType,
            possession,
            attributes
          };
          auth.push(item);
        }
      })
    })
    return auth;
  }


  get grants() {
    return this.formToGrants.map(auth => {
      let { resource, action, possession, attributes } = auth;
      return {
        role: 'user',
        resource,
        action: `${action}:${possession}`,
        attributes,
      }
    })
  }


  get input() {
    return this.grantsToFormInput(this.formToGrants);
  }



  clear() {
    this.reset();
  }

  reset() {
    this.grantsForm.reset(this.defaultValues);
    this.toggleAll();
  }


  grantsToFormInput(input: GrantStorageItem[]) {
    let data = {};
    input.forEach(auth => {
      let { resource, action, possession, attributes } = auth;
      data[resource] = data[resource] || {};
      data[resource][action] = { active: true, possession, attributes } as ActionItem;
    })
    return data;
  }

  submit() {
    if (!this.form.valid) {
      FormUtils.markAsDirty(this.form);
      return;
    }

    let data: any = {};
    data.name = this.form.value.name;
    data.grants = this.formToGrants;

    this.isLoading = true;
    if (!this.roleId) {
      this.sys.createRole(data).subscribe({
        next: () => {
          this.isLoading = false;
          this.onSuccess.emit(data);
          this.message.success($localize`角色创建成功`);
        },
        error: err => {
          this.isLoading = false;
          this.message.error(err.error?.message || err.message);
          this.onError.emit(err);
        }
      })
    } else {
      this.sys.updateRole(this.roleId, data).subscribe({
        next: () => {
          this.isLoading = false;
          this.onSuccess.emit(data);
          this.message.success($localize`角色更新成功`);
        },
        error: err => {
          this.isLoading = false;
          this.message.error(err.error?.message || err.message);
          this.onError.emit(err);
        }
      })
    }
  }

  get isDirty() { return FormUtils.isDirty(this.form) }



}

/**
 * 授权存储类型
 */
export interface GrantStorageItem {
  resource: string;
  action: ActionType;
  possession: PossessionType;
  attributes: string;
}

/**
 * 授权类型，用于初始化 AccessControl
 */
export interface GrantItem {
  role: string;
  resource: string;
  action: string;
  attributes: string;
}

/**
 * 表单数据 resource-action 
 */
export interface ActionItem {
  active: boolean;
  possession?: PossessionType;
  attributes?: string;
}


